文章目录
一、STL---string类
1. 常用构造函数
2. 常用操作
3. 字符串流处理
二、STL---容器
1. STL及基本概念
2. 顺序容器简介
3. 关联容器简介
4. 容器适配器简介
5. 常用成员函数
三、STL---迭代器
1. 普通迭代器
2. 双向、随机访问迭代器
3. 不同容器的迭代器
四、STL---常用算法
1. find顺序查找
2. binary_search二分查找
3. sort快速排序
五、其他知识点
一、STL---string类
1. 常用构造函数
string s1("hhh");
cout << s1 << endl;//hhh
string s2(8,'x');
cout << s2 << endl;//xxxxxxxx
string s;
s = 'a';
cout << s << endl;//a
string s1{'a','\0','b','c'};
cout << s1 << endl;//abc
cout << s1.length() << endl;//4
cout << s1.c_str() << endl;//以C语言风格打出,结果: a
2. 常用操作
2.1 获取长度:使用成员函数length()获取。
string s("hello");
cout << s.length() << endl;//打印5
2.2 支持流读取运算符:cin >> s; 以空格为结束。
string s;
cin >> s;//输入hello world
cout << s << endl;//打印hello
2.3 支持getline函数:getline(cin, s); 以换行为结束。
string s;
getline(cin, s);//输入hello world
cout << s << endl;//打印hello world
2.4 复制对象内容:①使用=赋值;②使用成员函数assign()。
string s1("hello");
//使用赋值=
string s2;
s2 = s1;
cout << s2 << endl;//打印hello
//使用成员函数assign()
string s3;
s3.assign(s1);
cout << s3 << endl;//打印hello
//assign函数实现部分复制
string s4;
s4.assign(s1, 1, 3);//复制s1中下标1开始的3字符
cout << s4 << endl;//打印ell
2.5 访问对象字符:①使用[]访问(常用);②使用成员函数at()访问。at()会做范围检查,若超出范围则抛出out of range异常,而[]访问方式不做范围检查。
string s("hello world");
//使用[]访问
for (int i = 0; i < s.length(); ++i) {
cout << s[i];
}
//使用at()访问
for (int i = 0; i < s.length(); ++i) {
cout << s.at(i);
}
2.6 连接字符串:①使用+=;②使用成员函数append。使用append可以实现部分增加。
string s1("hello ");
string s2("world ");
//使用+=在s1后增加s2
s1 += s2;
cout << s1 << endl;//打印hello world
//使用append在s2后增加s1
s2.append(s1);
cout << s2 << endl;//打印world hello world
//使用append在s1后增加s2中下标1开始的3字符
s1.append(s2, 1, 3);
cout << s1 << endl;//打印hello world orl
2.7 比较大小:①>、<、==、<=等关系运算符已经被重载了,返回值都是bool类型。②使用成员函数compare,返回值为0、1或-1。compare可以比较两个string的一部分。
string s1("hello ");
string s2("hella ");
//使用关系运算符比较
bool flag = (s1 < s2);
cout << flag << endl;//打印0
//使用compare比较一部分
int ret = s1.compare(1, 2, s2, 0, 3);//el与hel比较
cout << ret << endl;//打印-1
2.8 获取子串:使用成员函数substr。
string s1("hello world");
//substr(i, j)表示从下标i开始的j个字符
cout << s1.substr(6, 5) << endl;//打印world
2.9 交换string内容:使用成员函数swap。
string s1("hello world");
string s2(8, 'h');
s1.swap(s2);
cout << s1 << endl;//打印hhhhhhhh
cout << s2 << endl;//打印hello world
2.10 主串中查找子串:①从前往后找:使用成员函数find。②从后往前找:使用成员函数rfind。③从指定位置开始查找:s.find("ll", 1);从s下标为1的地方开始查找"ll"。若找到则返回子串在主串中的首下标,未找到返回string::npos静态变量(VS2022中定义为-1)。
string s1("hello world");
string s2("ll");
//从前往后找
int fronRet = s1.find(s2);
cout << fronRet << endl;//打印2
//从后往前找
int RearRet = s1.rfind(s2);
cout << RearRet << endl;//打印2
//从指定位置查找
int posRet = s1.find(s2, 4);//s1下标4开始查找
cout << posRet << endl;//打印-1表示没找到
2.11 删除内容:使用成员函数erase。
string s1("hello world");
s1.erase(5);//删除下标5以及之后的所有内容
cout << s1 << endl;//打印hello
cout << s1.length() << endl;//打印5
cout << s1.size() << endl;//打印5
2.12 替换内容:使用成员函数replace。
string s1("hello world");
s1.replace(2, 3, "xxxx");//将s1下标2开始的3字符替换为xxxx
cout << s1 << endl;//打印hexxxx world
2.13 插入内容:使用成员函数insert。
string s1("hello world");
string s2("insert");
//s1下标5插入s2
s1.insert(5, s2);
cout << s1 << endl;//打印helloinsert world
//s1下标0插入s2下标0开始的3字符
s1.insert(0, s2, 0, 3);
cout << s1 << endl;//打印inshelloinsert world
2.14 转换成C语言风格的字符串:①使用成员函数c_str(),返回const char*类型字符串,且该字符串以'\0'结尾。②使用成员函数data(),返回char*类型字符串,对其进行修改可能会出错。
string s1("hello world");
const char* s2 = s1.c_str();
printf("%s", s2);//打印hello world
3. 字符串流处理
(1) 字符串输入流:将字符串中的内容保存为指定变量。例如,将"hello world 2 A 5.6"分别保存为两个string类型、一个int类型、一个char类型和一个double类型。需要包含头文件#include <iostream>、#include <string>和#include <sstream>。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string target("hello world 2 A 5.6");
istringstream input(target);
//定义存储的变量
string s1, s2;
int n;
char c;
double d;
//字符串输入流
input >> s1 >> s2 >> n >> c >> d;
//打印结果
cout << s1 << endl;//打印hello
cout << s2 << endl;//打印world
cout << n << endl;//打印2
cout << c << endl;//打印A
cout << d << endl;//打印5.6
return 0;
}
(2) 字符串输出流:将某些变量的值以字符串形式呈现。例如,将"hello"、5和"world"存放于一个字符串中。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string s1("hello"), s2("world");
int a = 5;
//字符串输出流
ostringstream output;
output << s1 << s2 << a;
cout << output.str() << endl;//打印helloworld5
return 0;
}
二、STL---容器
1. STL及基本概念
1.1 STL:
- 是Standard Template Liabrary的缩写,即标准模板库。
- 标准模板库是常用数据结构和算法的模板的集合。它将常用的数据结构(如数组、集合和链表等)和常用的算法(如排序和查找等)写成类模板和函数模板。
1.2 基本概念:
- 容器:可容纳指定数据类型的数据结构,是类模板。对象被插入容器时,被插入的是对象的一个复制品。
- 顺序容器:vector(动态数组)、deque(双端队列)、list(循环双链表)
- 关联容器:set、multiset、map、multimap
- 容器适配器:stack(栈)、queue(队列)、priority_queue(优先级队列)
- 迭代器:可用于依次访问容器中的元素,类似于指针。
- 算法:用于操作容器中的元素,是函数模板。一些算法支持操作容器内部分元素,因此在传实参时要传入首尾元素的迭代器。在使用这些算法时,需要添加头文件<algorithm>
2. 顺序容器简介
- 顺序容器并非排序的,元素的插入位置与该元素的值无关。
- vector:头文件<vector> 动态数组,其大小可以动态变化。元素在内存里是连续存储的,通过下标可以访问某个元素,时间复杂度为O(1)。在头部或者中间位置插入或删除元素,时间复杂度为O(n)。在尾部插入和删除元素一般是常数时间,但是涉及扩容时会申请新空间,然后将已有的元素拷贝至新空间,时间复杂度为O(n)。
- deque:头文件<deque> 双端队列,元素在内存连续存放。随机存取任何元素的时间复杂度为O(1),但次于vector。在两端增删元素的时间复杂度大部分情况是O(1),因为只需要改变元素和移动头尾指针。但是,当涉及扩容时时间复杂度为O(n)。
- list:头文件<list> 循环双向链表,元素不是连续存储的,不支持随机存取操作。在已知位置的情况下,增删元素的时间复杂度为O(1),因为只需要更改相关的指针即可。
3. 关联容器简介
- 元素是排序的。在插入元素时,需要根据排序规则来确定其位置。通常以平衡二叉树的方式来实现,查找和插入的时间复杂度为O(log n)。
- set/multiset:头文件<set> 集合。set中不允许有相同的元素,multiset中允许有相同元素。
- map/multimap:头文件<map> 键值对,有且仅有两个成员变量first和second。first存放排序的关键字,根据first来排序所有对象,因此在查找时就能根据first快速定位。map不允许有相同的first,但multimap允许有相同的first。
- 关联容器支持以下成员函数:
find | 查找等于某个值的元素(判定等于的机制:x<y和y<x同时不成立) |
lower_bound | 查找某个值的下界区间,返回迭代器it,使得[begin, it)内所有值均小于指定值。 |
upper_bound | 查找某个值的上界区间,返回迭代器it,使得[it, end)内所有值均大于指定值。 |
equal_range | 同时查找lower_bound和upper_bound,返回pair<it,it> |
count | 计算等于某个值的元素个数(判定等于的机制同上) |
insert | 插入一个元素或一个区间 |
4. 容器适配器简介
- stack:头文件<stack> 栈。只能操作栈顶的元素,符合后进先出的原则。
- queue:头文件<queue> 单向队列。只能在队头进行删除、查找和修改,只能在队尾进行插入。符合先进先出的原则。
- priority_queue:头文件<queue> 优先级队列。最高优先级元素总是第一个出队。
5. 常用成员函数
5.1 顺序容器和关联容器都有的成员函数:
begin 返回第一个元素的迭代器 end 返回最后一个元素后面位置的迭代器 rbegin 返回最后一个元素的迭代器 rend 返回第一个元素的前面位置的迭代器 erase 删除一个或多个元素 clear 删除所有元素
5.2 顺序容器常用的成员函数:
front 返回第一个元素的引用 back 返回最后一个元素的引用 push_back 在容器末尾增加新元素 pop_back 删除容器末尾的元素 erase 删除迭代器指向的元素(可能会使该迭代器失效)。也可以删除一个区间,返回被删除元素后面邻接元素的迭代器。
三、STL---迭代器
1. 普通迭代器
1.1 迭代器简介:
- 是一种访问顺序和关联容器元素的“中介”。
- 存在const和非const两种。对于const迭代器,只能访问元素;对于非const迭代器,可以访问和修改元素。
1.2 定义迭代器:
- 方式一:"容器类名::iterator 变量名;"
- 方式二:"容器类名::const_iterator 变量名;"
1.3 访问迭代器指向的元素:"*迭代器变量名"。注意:迭代器可以使用++操作来指向后一个元素,但是当其指向的地址已经超出容器范围,就会报错。
1.4 代码示例:常量迭代器、非常量迭代器、反向迭代器
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <vector> using namespace std; int main() { //创建vector容器 vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); //常量迭代器 vector<int>::const_iterator i; for (i = v.begin(); i != v.end(); i++) { cout << *i << " "; } cout << endl; //非常量迭代器 vector<int>::iterator j; for (j = v.begin(); j != v.end(); j++) { (*j)++; cout << *j << " "; } cout << endl; //反向迭代器 vector<int>::reverse_iterator r; for (r = v.rbegin(); r != v.rend(); r++) { cout << *r << " "; } cout << endl; return 0; }
2. 双向、随机访问迭代器
- 双向迭代器不仅能往后访问容器元素,还能使用--往前访问元素。
- 注意:双向迭代器在遍历时,不能使用<来比较临界条件,而只能用!=。
- 随机访问迭代器支持以下操作:
p+=i | p向后移动i个元素 |
p-=i | p向前移动i个元素 |
p+i | 其值为p后第i个元素的迭代器 |
p-i | 其值为p前第i个元素的迭代器 |
p[i] | 其值为p后第i个元素的引用 |
p<p1等比较 | 比较p和p1的前后位置 |
3. 不同容器的迭代器
vector | 随机访问迭代器 |
deque | 随机访问迭代器 |
list | 双向迭代器 |
set/multiset | 双向迭代器 |
map/multimap | 双向迭代器 |
stack | 不支持 |
queue | 不支持 |
priority_queue | 不支持 |
注意:有些算法需要用到随机访问迭代器,那么这些算法就不适用于双向迭代器和不支持迭代器的容器。
四、STL---常用算法
1. find顺序查找
(1) 函数模板:
template <class Inlt, class T> Inlt find(Inlt first, Inlt last, const T& val);
(2) 参数说明:
- first和last分别是容器迭代器的查找区间起点和终点,查找范围为[first, last)。
- val为查找的元素,内部使用==判断是否相等。
- 返回值:若找到元素,则返回指向该元素的迭代器;否则返回指向last的迭代器。
(3) 代码示例:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { //创建vector容器对象 vector<int> v; v.push_back(24); v.push_back(4); v.push_back(5); v.push_back(16); //find顺序查找元素 vector<int>::iterator p; p = find(v.begin(), v.end(), 1);//查找范围:[24,4,5,16] if (p != v.end()) cout << "找到了:" << *p << endl; else cout << "未找到!" << endl; return 0; }
2. binary_search二分查找
前提需要将容器排序。具体细节见C++中的binary_search函数详解_c++ binary search-CSDN博客。
3. sort快速排序
默认是从小到大排序的,若手动传入比较函数则可以自定义比较方式。不支持随机存取特性的容器无法使用。但是往往这些容器内会有成员函数sort可以调用,例如list。具体细节见sort()函数——C++标准库函数_sort函数头文件-CSDN博客。
五、其他知识点
【1】vector容器创建二维动态数组:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <vector> using namespace std; int main() { //创建二维数组 vector< vector<int> > v(3); for (int i = 0; i < v.size(); i++) { for (int j = 0; j < i + 1; j++) { v[i].push_back(j); } } //遍历二维数组元素 for (int i = 0; i < v.size(); i++) { for (int j = 0; j < v[i].size(); j++) { cout << v[i][j] << " "; } cout << endl; } return 0; }
【2】list成员函数:
list除了具有顺序容器都有的成员函数外,还具有如下的成员函数:
push_front 在前面插入 pop_front 在前面弹出 sort 排序。由于list不支持随机访问,无法采用STL算法的sort remove 删除和指定值相同的所有元素 unique 删除所有与前一个元素相同的元素 merge 合并两个链表,并清空被合并的那个。注意:merge调用前需要将这两个链表排序,否则运行错误。 reverse 翻转链表 splice 在指定位置插入另一链表中的一个或多个元素,并删除另一链表中被插入的元素。
【3】list代码示例:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <list> #include <algorithm> using namespace std; //定义A类 class A { private: int n; public: A(int n) : n(n) {} friend ostream& operator<<(ostream& cout, const A& p) { cout << p.n; return cout; } friend bool operator<(const A& p1, const A& p2) { return p1.n < p2.n; } friend bool operator==(const A& p1, const A& p2) { return p1.n == p2.n; } }; //打印list的函数模板 template <class T> void printList(const list<T> & lst) { typename list<T>::const_iterator p; for (p = lst.begin(); p != lst.end(); p++) { cout << *p << " "; } cout << endl; } int main() { //创建list1: 2 3 4 1 1 list<A> list1; list1.push_back(2); list1.push_back(3); list1.push_back(4); list1.push_back(1); list1.push_back(1); cout << "list1: "; printList(list1); //创建list2: 40 10 15 30 65 85 list <A> list2; list2.push_back(15); list2.push_front(10); list2.push_front(40); list2.push_back(30); list2.push_back(65); list2.push_back(85); cout << "list2: "; printList(list2); //给两个list排序 list1.sort(); list2.sort(); cout << "排序后的list1: "; printList(list1); cout << "排序后的list2: "; printList(list2); //将list2融入list1,并清空list2 list1.merge(list2); cout << "融合后的list1: "; printList(list1); return 0; }
【4】函数对象:若一个类重载了运算符(),那么这个类创建的对象就是函数对象。
class A { public: //重载运算符() int operator()(int a, int b, int c) { return a + b + c; } }; A a;//函数对象 cout << a(1, 2, 3) << endl;//等价于a.operator()(1,2,3)