C++----STL(string)

引言:STL简介

什么是STL

STL(standard template libaray-标准模板库): C++标准库的重要组成部分(注意:STL只是C++标准库里的一部分,cin和cout也是属于C++标准库的),不仅是一个可复用的组件库,而且 是一个包罗数据结构与算法的软件框架

STL的六大组件

af932adec1e04c279182ebb3831a1bd8.png

 string类

概念

string是管理字符数组的顺序表。

标准库中的string

sting类的文档介绍连接:cplusplus.com/reference/string/string/?kw=string

string类的常用接口说明

1.常见构造

 注意:

#include<iostream>
using namespace std;

int main()
{
	string s1;
	string s2("张三");// string (const char* s);
	string s3("hello world");
	string s4(10, '*');// string (size_t n, char c);
	string s5(s2);// string (const string& str);

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s4 << endl;
	cout << s5 << endl;

    // 使用s3的子串初始化s6,从索引6开始,长度为5的子串,即"world"
	string s6(s3, 6, 5);// string (const string& str, size_t pos, size_t len = npos);
	cout << s3 << endl;
	cout << s6 << endl;

    // 使用s3的子串初始化s7,从索引6开始到s3的末尾,即"world"
	string s7(s3, 6);
	cout << s7 << endl;

	string s8(s3, 6, 100);// 尝试从s3的索引6开始获取长度为100的子串,但s3的长度不足,所以只取到s3的末尾,即"world"
	cout << s8 << endl;

	string url("https://en.cppreference.com/w/");
	string sub1(url, 0, 5);
	string sub2(url, 8, 15);
	string sub3(url, 22);
	cout << sub1 << endl;
	cout << sub2 << endl;
	cout << sub3 << endl;
	return 0;
}

2.赋值操作

#include<iostream>
using namespace std;

int main()
{
	string s1;
	string s2("张三");
	s1 = s2;
	cout << s1 << endl;
	
	return 0;
}

3.容量操作

注意:
  1. size()length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. reserve(size_t res_arg=0):在C++的string使用中,调用reserve(100)函数理论上应确保字符串对象至少预留足够的空间来存储100个字符(不包括终止的空字符\0)。然而,实际预留的空间大小可能因编译器和库实现的不同而有所差异。在GCC等Linux环境下的编译器中,string的实现可能会严格遵守reserve的请求,调用后capacity()返回的值接近或等于100。而在VS(特别是VS2013及更早版本)中,由于可能采用了“短字符串优化”技术,调用reserve(100)capacity()返回的值可能会远大于100,以减少未来内存分配的次数。此外,不同编译器和库实现中的string类对于内存管理的策略(如释放多余空间和扩大容量等)也可能有所不同。值得注意的是,为string预留空间时,如果reserve的参数小于字符串当前的底层空间总大小,那么reserve不会改变其容量大小。
  4. resize(size_t n) resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
#include<iostream>
using namespace std;

void test_size_lenth_capacity()
{
	string s1 = "Hello World!";
	cout << s1.size() << endl;
	cout << s1.length() << endl;
	cout << s1.capacity() << endl;
	if (!s1.empty()) {
		s1.clear();
		cout << s1.empty() << endl;
		cout << s1.size() << endl;//清除后的有效字符个数会变
		cout << s1.length() << endl;
		cout << s1.capacity() << endl;//但是清除后的容量不会变
	}
}

void testReserve()
{
	string s;
	s.reserve(100);
	size_t sz = s.capacity();
	cout << "capacity changed: " << sz << '\n';


	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}

	s.clear();
	cout << "capacity changed: " << sz << '\n';

	s.reserve(10);
	sz = s.capacity();
	cout << "capacity changed: " << sz << '\n';
}

void testResize()
{
	string s1 = "Hello World!";
	s1.reserve(50);
	cout << "Reserved capacity of string: " << s1.capacity() << endl;

	// resize: 改变字符串的大小,如果新大小大于当前大小,则填充字符(默认是空字符)
	s1.resize(20, '*');
	cout << "Resized string: " << s1 << endl;
}

void test_shrink_to_fit()
{
	string s1 = "Hello World!";
	cout << "Current capacity of string: " << s1.capacity() << endl;
	s1.reserve(50);
	cout << "Reserved capacity of string: " << s1.capacity() << endl;
	s1.shrink_to_fit();
	cout << "shrink the capacity of s1 to fit: " << s1.capacity() << endl;
}

4.访问及遍历操作

注意:operator[]有两种形式用于访问字符串中的字符
  • 非const版本:用于非常量字符串,允许读取和修改字符。例如,str[i] = 'A'; 可以改变字符串str中索引为i的字符。
  • const版本:用于常量字符串或当您不希望修改字符串时,它只允许读取字符而不允许修改。尝试修改const字符串中的字符会导致编译错误。
重点补充:迭代器
定义

迭代器(iterator)是一种类似指针的对象,用于访问容器中的元素。它可能是一个指针,也可能是一个封装了指针行为的对象。迭代器提供了对容器元素的顺序访问,可以遍历容器中的元素。

迭代器的使用

1.普通迭代器和反向迭代器的使用

普通迭代器允许读写容器中的元素,反向迭代器允许我们从后向前遍历容器。以下是一个使用迭代器遍历并修改 string 对象的例子:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s1("hello world");

    //普通迭代器
    string::iterator it = s1.begin();
    while (it != s1.end()) {
        (*it)--;  // 将每个字符的ASCII值减1
        ++it;
    }
    cout << s1 << endl;  // 输出修改后的字符串

    //反向迭代器
    auto rit = s1.rbegin();// 使用auto关键字简化类型声明
    while (rit != s1.rend())
    {
	    (*rit) ++;// 将每个字符的ASCII值加1
	    ++rit;
    }
    cout << s1 << endl;

    return 0;
}

2.const迭代器的使用

对于 const 对象或需要保证不修改容器内容的场景,应使用 const 迭代器。const 迭代器只能读取元素,不能修改。

#include <iostream>
#include <string>
using namespace std;

void Func(const std::string& s) {
    string::const_iterator it = s.begin();
    while (it != s.end()) {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    auto rit = s.rbegin();  // 使用auto关键字简化类型声明
    while (rit != s.rend()) {
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
}

int main() {
    string s1("hello world");
    Func(s1);
    return 0;
}
迭代器的意义
  1. 修改元素:迭代器可以像指针一样解引用并修改元素(在非 const 迭代器的情况下)。

  2. 范围for循环:C++11引入了范围for循环,底层通过迭代器实现,简化了遍历容器的代码。

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        string s1("hello world");
        for (auto& ch : s1) {
            ch++;  // 将每个字符的ASCII值加1
        }
        cout << s1 << endl;
    
        for (char ch : s1) {
            cout << ch << " ";
        }
        cout << endl;
        return 0;
    }
  3. 通用性:几乎所有标准容器(如 vectorlistmap 等)都支持迭代器,并且用法类似。这使得代码更加通用和可移植。

    #include <iostream>
    #include <vector>
    #include <list>
    using namespace std;
    
    int main() {
        vector<int> v = {1, 2, 3, 4};
        vector<int>::iterator vit = v.begin();
        while (vit != v.end()) {
            cout << *vit << " ";
            ++vit;
        }
        cout << endl;
    
        list<int> lt = {10, 20, 3, 4};
        list<int>::iterator lit = lt.begin();
        while (lit != lt.end()) {
            cout << *lit << " ";
            ++lit;
        }
        cout << endl;
        return 0;
    }
  4. 限制:对于非连续存储的容器(如 listmap),不能使用下标操作符 [] 访问元素,因为它们的空间结构不是连续的。

  5. 与算法配合:STL算法(如 reversesort 等)通过迭代器操作容器中的元素,使得算法与容器解耦,提高了代码的灵活性和复用性。

    #include <iostream>
    #include <vector>
    #include <list>
    #include <algorithm>
    using namespace std;
    
    int main() {
        vector<int> v = {1, 2, 3, 4};
        list<int> lt = {10, 20, 3, 4};
    
        reverse(v.begin(), v.end());
        reverse(lt.begin(), lt.end());
    
        for (auto e : v) {
            cout << e << " ";
        }
        cout << endl;
    
        for (auto e : lt) {
            cout << e << " ";
        }
        cout << endl;
    
        sort(v.begin(), v.end());
        for (auto e : v) {
            cout << e << " ";
        }
        cout << endl;
    
        return 0;
    }
补充:at的代码示例
void testAt()
{
	string s1 = "Hello World!";
	cout << s1.at(2) << endl;

	s1.at(2) = 'O';
	cout << s1 << endl;
}

5.修改操作

函数名称功能说明
push_back在字符串末尾添加一个字符
append在字符串末尾追加一个字符串
operator+=使用加法运算符追加字符串或字符
assign覆盖赋值,用新字符串替换原字符串内容
insert在指定位置插入字符串或字符(不建议频繁使用,会影响效率)
erase删除指定位置或范围内的字符(不建议频繁使用,会影响效率)
pop_back删除字符串末尾的字符
replace替换指定范围内的字符为新的字符串或字符
void test01()
{
    string s1("hello world");
    s1.append("ssssss"); // s1 变为 "hello worldssssss"
    s1.push_back('a'); // s1 变为 "hello worldssssssa"
    s1+=" abc"; // s1 变为 "hello worldssssssa abc"
    s1.assign("111111111"); // s1 变为 "111111111"

    s1.insert(0, "hello"); // s1 变为 "hello111111111"
    s1.insert(5, "world"); // s1 变为 "helloworld11111"
    s1.insert(0, 10, 'x'); // s1 变为 "xxxxxxxxxxhelloworld111"
    s1.insert(s1.begin()+10, 10, 'y'); // s1 变为 "xxxxxxxxxxhyyyyyyyworld11"
}

void test02()
{
    string s1("hello world");
    s1.erase(5, 1); // 删除从位置5开始的1个字符,s1 变为 "hello world" -> "helloworld"
    s1.erase(5); // 删除从位置5开始的剩余所有字符(默认行为),s1 变为 "hello"
    string s2("hello world");
    s2.erase(0, 1); // 删除从位置0开始的1个字符,s2 变为 "hello world" -> "ello world"
    s2.erase(s2.begin()); // 删除迭代器指向的第一个字符,s2 变为 "llo world"
}

void test03()
{
	//world替换成 xxxxxxxxxxxxxxxxxxxxxx
	string s1("hello world hello lynn");
	s1.replace(6, 5, "xxxxxxxxxxxxxxxxxxxxxx"); // 替换 "world" 为 "xxxxxxxxxxxxxxxxxxxxxx"
	cout << s1 << endl; // 再次替换,s1 变为 "hello yyyyy"

	s1.replace(6, 23, "yyyyy");
	cout << s1 << endl;

	// 所有空格替换成20%
	string s2("hello world hello bit");
	string s3;
	for (auto ch : s2)
	{
		if (ch != ' ')
		{
			s3 += ch;
		}
		else
		{
			s3 += "20%";
		}
	}

	s2 = s3; // s2 变为 "hello20%world20%hello20%lynn"
}

6.字符串操作

函数名称功能说明
c_str返回一个指向以空字符结尾的字符数组的指针,该字符数组是字符串的副本,常用于与C语言接口函数的交互。
find用于查找子字符串或字符在字符串中第一次出现的位置。
rfind用于查找子字符串或字符在字符串中最后一次出现的位置。
find_first_of用于查找字符串中第一次出现参数中任一字符的位置。
find_last_of用于查找字符串中最后一次出现参数中任一字符的位置。
substr用于查找字符串中最后一次出现参数中任一字符的位置。
void test_c_str() {
    string str = "Hello, World!";
    const char* cStr = str.c_str();
    cout << cStr << endl; // 输出: Hello, World!
}

void test_find() {
    string str = "Hello, World!";
    size_t pos = str.find("World");
    if (pos != string::npos) {
        cout << "Found 'World' at position: " << pos << endl; // 输出: Found 'World' at position: 7
    }
    else {
        cout << "'World' not found" << endl;
    }
}

void test_rfind() {
    string str = "Hello, Hello World!";
    size_t pos = str.rfind("Hello");
    if (pos != string::npos) {
        cout << "Found 'Hello' last time at position: " << pos << endl; // 输出: Found 'Hello' last time at position: 13
    }
    else {
        cout << "'Hello' not found" << endl;
    }
}

void test_find_first_of() {
    string str = "Hello, World!";
    size_t pos = str.find_first_of("aeiou");
    if (pos != string::npos) {
        cout << "Found first vowel at position: " << pos << endl; // 输出: Found first vowel at position: 1 (e in Hello)
    }
    else {
        cout << "No vowel found" << endl;
    }
}

void test_find_last_of() {
    string str = "Hello, World!";
    size_t pos = str.find_last_of("aeiou");
    if (pos != string::npos) {
        cout << "Found last vowel at position: " << pos << endl; // 输出: Found last vowel at position: 8 (o in World)
    }
    else {
        cout << "No vowel found" << endl;
    }
}

void test_substr() {
    string str = "Hello, World!";
    string subStr1 = str.substr(7, 5); // 从位置7开始,长度为5的子字符串
    cout << "Substring1: " << subStr1 << endl; // 输出: Substring1: World

    string subStr2 = str.substr(2, 6); // 从位置2开始,长度为6的子字符串
    cout << "Substring2: " << subStr2 << endl; // 输出: Substring2: llo, W
}

7.string类非成员函数

函数名称功能说明
operator<<重载输出流运算符<<用于将自定义类型的数据输出到输出流。
operator>>重载输入流运算符>>用于从输入流中读取数据到自定义类型。
getlinegetline 是标准库函数,用于从输入流中读取一行文本,直到遇到换行符('\n'),换行符会被丢弃,不会存储在字符串中。
operator+重载operator+用于连接两个字符串。

operator==、operator>、

operator<、

operator<=、

operator>=、

operator!=

重载关系运算符(如==, <, >, <=, >=, !=)用于比较自定义类型的对象。

当使用关系运算符比较两个字符串时,比较是逐字符进行的,基于Unicode码点值。

#include<algorithm>
using namespace std;

int main() {
    string s1, s2;
    cin >> s1;//如果输入空格,就会停止输入
    cout << s1 << endl;

    //注意:如果 cin >> s1; 读取后留下了换行符,getline() 会立即读取到这个换行符并停
    //     止读取,认为已经读取了一行(实际上是一个空行)。因此,s2 会是一个空字符串。
    //     为了避免这种问题,我们要通过cin.ignore(); 忽略缓冲区中的换行符。
    cin.ignore();// 忽略缓冲区中的下一个字符(通常是换行符)
    getline(cin, s2);//如果输入空格,不会停止输入,直到遇到换行符'\n',才会停止输入
    cout << s2 << endl;
    string s3 = s1 + s2;
    cout << s3 << endl;

    string s4, s5;
    s4 = "abcd";
    s5 = "abc";
    if (s4 > s5) {
        cout << "s4 > s5" << endl;
    }
    else {
        cout << "s4 <= s5" << endl;
    }
    return 0;
}

8.字符串转换函数

函数名称功能说明

stoi

将字符串转换为整数(int

stof

将字符串转换为单精度浮点数(float

stod

将字符串转换为双精度浮点数(double

stoll

将字符串转换为长长整数(long long

to_string

将数值转换为字符串

int main() {
    string str1 = "123";
    int num1 = stoi(str1);
    cout << "The int value is: " << num1 << endl;

    string str2 = "123.456";
    float num2 = stof(str2);
    cout << "The float value is: " << num2 << endl;

    string str3 = "123";
    double num3 = stod(str3);
    cout << "The double value is: " << num3 << endl;

    string str4 = "12345678910111213";
    long long num4 = stoll(str4);
    cout << "The long long value is: " << num4 << endl;

    int num5 = 123;
    string str5 = to_string(num5);
    cout << "The string value is: " << str5 << endl;

    long long num6 = 1234567;
    string str6 = to_string(num6);
    cout << "The string value is: " << str6 << endl;

    double num7 = 3.14;
    string str7 = to_string(num7);
    cout << "The string value is: " << str7 << endl;
    return 0;
}

写时拷贝(了解)

一、浅拷贝问题

  1. 析构两次:浅拷贝只复制了对象的指针,导致两个对象共享同一块内存。当这两个对象被分别析构时,会尝试对同一块内存进行两次释放,从而引发错误。
  2. 一个对象修改会影响另一个:由于浅拷贝只是复制了指针,所以两个对象实际上指向的是同一块数据。因此,当一个对象的数据被修改时,另一个对象的数据也会相应地被改变。

二、深拷贝问题

  1. 内存开销:深拷贝需要复制对象的所有数据,包括嵌套对象,这可能导致较大的内存开销。
  2. 写时拷贝优化:为解决深拷贝的内存开销问题,可采用写时拷贝策略。
    初始时,对象间共享数据内存,引用计数跟踪使用对象数量。
    当某个对象尝试修改数据时,若引用计数大于1,则进行深拷贝,生成新的数据副本,以避免影响其他对象。
  3. 引用计数管理
    (注意:引用计数需正确管理,以确保内存安全释放。)
    当对象被复制时,引用计数增加;当对象被销毁或不再被引用时,引用计数减少。
    引用计数降为0时,释放对象及其数据内存。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953913.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何选择视频文件

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何选择多个图片文件"相关的内容&#xff0c;本章回中将介绍如何选择视频文件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在前…

C++中的STL

STL&#xff08;标准模板库&#xff09;在广义上分为&#xff1a;容器&#xff0c;算法&#xff0c;迭代器 容器和算法之间通过迭代器进行无缝衔接 STL大体上分为六大组件:分别为容器&#xff0c;算法&#xff0c;迭代器&#xff0c;仿函数&#xff0c;适配器&#xff0c;空间…

Windows下安装和配置Go开发环境

文章目录 1. 介绍了SDK2. 下载 SDK工具包3. windows 下配置 Golang 环境变量 1. 介绍了SDK SDK 的全称(Software Development Kit 软件开发工具包)SDK是提供给开发人员使用的&#xff0c;其中包含了对应开发语言的工具包 2. 下载 SDK工具包 Go语言的官网为&#xff1a;https…

riscv架构下linux4.15实现early打印

在高版本linux6.12.7源码中&#xff0c;early console介绍&#xff0c;可参考《riscv架构下linux6.12.7实现early打印》文章。 1 什么是early打印 适配内核到新的平台&#xff0c;基本环境搭建好之后&#xff0c;首要的就是要调通串口&#xff0c;方便后面的信息打印。 正常流…

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载,Scroll滚动到顶部

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载 效果展示 使用方法 import LoadingText from "../components/LoadingText" import PageToRefresh from "../components/PageToRefresh" import FooterBar from "../components/…

《自动驾驶与机器人中的SLAM技术》ch9:自动驾驶车辆的离线地图构建

目录 1 点云建图的流程 2 前端实现 2.1 前端流程 2.2 前端结果 3 后端位姿图优化与异常值剔除 3.1 两阶段优化流程 3.2 优化结果 ① 第一阶段优化结果 ② 第二阶段优化结果 4 回环检测 4.1 回环检测流程 ① 遍历第一阶段优化轨迹中的关键帧。 ② 并发计算候选回环对…

鸿蒙面试 2025-01-10

写了鉴权工具&#xff0c;你在项目中申请了那些权限&#xff1f;&#xff08;常用权限&#xff09; 位置权限 &#xff1a; ohos.permission.LOCATION_IN_BACKGROUND&#xff1a;允许应用在后台访问位置信息。 ohos.permission.LOCATION&#xff1a;允许应用访问精确的位置信息…

Windows图形界面(GUI)-QT-C/C++ - QT控件创建管理初始化

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 控件创建 包含对应控件类型头文件 实例化控件类对象 控件设置 设置父控件 设置窗口标题 设置控件大小 设置控件坐标 设置文本颜色和背景颜色 控件排版 垂直布局 QVBoxLayout …

Unreal Engine 5 C++ Advanced Action RPG 七章笔记

第七章 Ranged Enemy 2-Ranged Enemy Starting Weapon 制作新敌人的流程准备 新敌人的武器起始的状态数据自己的战斗能力投射能力自己的行为树 创建角色,添加武器,添加数据,就是继承之前的基类敌人的 运行结果 3-Glacer Starting Stats 看看就行,就是复制曲线表格更改数…

funcaptcha手势指向验证码识别

注意&#xff0c;本文只提供学习的思路&#xff0c;严禁违反法律以及破坏信息系统等行为&#xff0c;本文只提供思路 如有侵犯&#xff0c;请联系作者下架 本文滑块识别已同步上线至OCR识别网站&#xff1a; http://yxlocr.nat300.top/ocr/other/21 该验证码会给出某物品所有的…

GAMES101学习笔记(三):Rasterization 光栅化(三角形的离散化、抗锯齿、深度测试)

文章目录 视口变换 Viewport三角形网格 Triangle Mesh采样 Sampling走样/反走样 Aliasing/Antialiasing采样频率、空间域与频率域深入理解采样、走样、反走样反走样总结深度测试 Depth testing 课程资源&#xff1a;GAMES101-现代计算机图形学入门-闫令琪 Lec5 ~ Lec6 学习笔记…

vscode 扩展Cline、Continue的差别?

Cline和Continue都是VSCode的AI编程插件&#xff0c;它们在功能、用户体验、性能、适用场景以及配置和使用步骤等方面存在一些差别&#xff1a; 一、功能差异 编辑功能 Cline&#xff1a;能够分析项目的文件结构和源代码抽象语法树&#xff08;AST&#xff09;&#xff0c;通…

鸿蒙打包发布

HarmonyOS应用/元服务发布&#xff08;打包发布&#xff09; https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-publish-app-V13?catalogVersionV13 密钥&#xff1a;包含非对称加密中使用的公钥和私钥&#xff0c;存储在密钥库文件中&#xff0c;格式…

晨辉面试抽签和评分管理系统之九:随机编排考生的分组(以教师资格考试面试为例)

晨辉面试抽签和评分管理系统&#xff08;下载地址:www.chenhuisoft.cn&#xff09;是公务员招录面试、教师资格考试面试、企业招录面试等各类面试通用的考生编排、考生入场抽签、候考室倒计时管理、面试考官抽签、面试评分记录和成绩核算的面试全流程信息化管理软件。提供了考生…

sparkRDD教程之必会的题目

1.前期准备 &#xff08;1&#xff09;看看上一期的博客&#xff0c;最好跟着上一期的博客把sparkRDD的基本命令给熟练掌握后&#xff0c;再来做这篇文章的任务。 上一期的博客&#xff1a;sparkRDD教程之基本命令-CSDN博客 &#xff08;2&#xff09;新建文件task6.scala …

stack和queue专题

文章目录 stack最小栈题目解析代码 栈的压入弹出序列题目解析代码 queue二叉树的层序遍历题目解析代码 stack stack和queue都是空间适配器 最小栈 最小栈的题目链接 题目解析 minst是空就进栈&#xff0c;或者是val < minst.top()就进栈 代码 class MinStack { public:M…

欧拉路径算法

欧拉图&#xff1a; 对于应该连通图G&#xff0c;有&#xff1a; 1欧拉路径&#xff1a;一条路径&#xff0c;它能够不重复地遍历完所有的边&#xff0c;这个性质很像不重复地一笔画完所有边&#xff0c;所以有些涉及到欧拉路径的问题叫做一笔画问题。 2欧拉回路&#xff1a…

【C#设计模式(23)——模板方法模式(Template Method Pattern)】

前言 在抽象类中封装算法的结构&#xff0c;具体的实现步骤由子类定义&#xff0c;从而达到不改变算法结构的&#xff0c;允许子类重定义方法内容。代码 public abstract class Teamplate {public void TeamplateMethod(){Step1();Step2();Step3();}protected abstract void …

MyBatis——XML映射文件

在MyBatis中&#xff0c;既可以通过注解的方式配置SQL语句&#xff0c;也可以通过XML映射文件的方式配置SQL语句。对于简单的SQL语句建议直接通过注解的方式配置SQL语句&#xff1a; Delete("delete from user where id#{id}") Integer deleteById(Integer id);但是…

Mysql--运维篇--安全性(数据库访问控制,最小权限原则,表空间加密,TLS加密,证书签发,SQL注入及防范等)

一、数据库访问控制 MySQL的访问控制是确保数据库安全的关键机制之一。通过合理的用户权限管理和访问控制策略&#xff0c;可以防止未经授权的用户访问、修改或删除敏感数据。 1、MySQL访问控制的工作原理 MySQL使用基于用户的访问控制模型&#xff0c;每个用户都有特定的权…