1 STL概论
STL(标准模板库):
STL的分类:容器,算法和迭代器。
STL提供了6大组件:容器,算法和迭代器,仿函数、适配器(配接器)、空间配置器。
2 三大组件的初识
容器:
| #define _CRT_SECURE_NO_WARNINGS |
| #include <iostream> |
| using namespace std; |
| #include <vector> |
| |
| |
| |
| |
| void test01() { |
| int array[5] = {1,3,5,6,8}; |
| int *p = array; |
| for (int i = 0; i < 5;i++) { |
| |
| cout << *(p++) << " "; |
| } |
| } |
| |
| void test02() { |
| |
| vector<int> v; |
| |
| v.push_back(1); |
| v.push_back(2); |
| v.push_back(3); |
| v.push_back(4); |
| |
| |
| |
| |
| |
| vector<int>::iterator itBegin = v.begin(); |
| vector<int>::iterator itEnd = v.end(); |
| |
| while (itBegin != itEnd) { |
| cout << *itBegin << " "; |
| |
| itBegin++; |
| } |
| } |
| |
| int main() |
| { |
| test02(); |
| system("pause"); |
| return EXIT_SUCCESS; |
| } |
总结: 普通的指针也是一种迭代器
C++容器类 vector ,vector 自带的迭代器vector <T> ::iterator
四种遍历方法:
第1种:直接使用while循环
| |
| vector<int>::iterator itBegin = v.begin(); |
| vector<int>::iterator itEnd = v.end(); |
| |
| |
| |
| |
| |
| |
| |
第2种:使用for循环
| for (vector<int>::iterator start = v.begin(); start != v.end(); start++) { |
| cout << *start << " "; |
| } |
第3种:使用foreach循环
| for ( int a: v) { |
| cout << a << " "; |
| } |
第4种: 使用algorithm头文件中的for_each函数
| for_each(v.begin(),v.end(),myPrint); |
总结: 迭代器可以看作指针。
vector对象的begin()函数返回的值就是指向vector容器第一个元素的指针。
3 string容器
3.1 构造和赋值
| |
| string str; |
| string str2(str); |
| string str3 = str2; |
| |
| string str4("abc"); |
| string str5(10, 'a'); |
| |
| cout << str4 << endl; |
| cout << str5 << endl; |
| |
| |
| str = "Hello"; |
| cout << str << endl; |
| str2 = str4; |
| str = 'a'; |
| cout << str << endl; |
| |
| str3.assign("fyeuryue",5); |
| cout << str3 << endl; |
| str3.assign("fyeuryue", 1,5); |
| cout << str3 << endl; |
3.2 存储
从string容器中取出元素的两种方法:
1. 使用方括号 [idnex]
2. 使用at(index)函数
3.3 字符串拼接
直接使用”+”运算符,或者调用append()函数
| string s1 = "hello"; |
| string s2; |
| s2 += " world"; |
| |
| s1.append("lofly"); |
| cout << s1 + s2 << endl; |
3.4 字符串查找
| 调用find() |
| int position = s1.find('o', 0); |
| cout << position << endl; |
| position = s1.rfind('o'); |
| cout << position << endl; |
3.5 字符串替换
| |
| s1.replace(0, 3, "llh"); |
| cout << s1 << endl; |
3.6 字符串比较
| |
| string t1 = "abc"; |
| string t2 = "abc"; |
| |
| if (t1.compare(t2) == 0) { |
| cout << "字符串相等" << endl; |
| } |
| else if(t1.compare(t2) == 1){ |
| cout << "t1大于t2" << endl; |
| } |
| else { |
| cout << "t1小于t2" << endl; |
| } |
3.7 string子串
| |
| string ss1 = "csadhfu"; |
| string ss2 = ss1.substr(2,5); |
| cout << ss2 << endl; |
3.8 string 的插入和删除
| |
| string str1 = "hello"; |
| str1.insert(1,"SB"); |
| cout << str1 << endl; |
| |
| str1.erase(1,2); |
| cout << str1 << endl; |
3.9 string 和 c-style类型转换
| |
| string s1 = "abc"; |
| const char *cstr = s1.c_str(); |
| |
| cout << cstr << endl; |
| printf("%s \n", cstr); |
| |
| string s2(cstr); |
| cout << s2 << endl; |
3.10 string赋值重新分配内存问题
| string s = "abcdefghi"; |
| char &a = s[1]; |
| char &b = s[2]; |
| a = 'm'; |
| b = 'n'; |
| cout << s << endl; |
| cout << "字符串的地址" << (int*)s.c_str() << endl; |
| |
| s = "ppppp"; |
| s = "pppppppppppppppppppppppppppp"; |
| |
| cout << s << endl; |
| cout << "字符串的地址" << (int*)s.c_str() << endl; |
| |
| |
| string s = "abRdefg"; |
| for (int i = 0; i < s.size();i++) { |
| s[i] = toupper(s[i]); |
| } |
| |
| cout << s << endl; |
转小写使用函数 tolower()
4 vector容器

vector的容器容量并非是线性增加的。
4.1 vector的数据结构
vector采用的是线性连空间。
注:动态增加大小的原理:为了能有更合适的控件,需要重新开辟一个更大的空间,将原来的数据拷贝到这个空间中。对vector的操作,一但空间重新分配了,指向原vector的所有的迭代器都会失效。
4.2 常用API操作
| |
| vector<int> v; |
| int a[] = {1,2,3,4,5}; |
| vector<int> v1(a,a+sizeof(a)/sizeof(int)); |
| vector<int> v2(v1.begin(),v1.end()); |
| printVector(v2); |
| |
| vector<int> v3(10,100); |
| printVector(v3); |
| |
| |
| vector<int> v4(v3.begin(),v3.end()-1); |
| printVector(v4); |
| |
| v4.swap(v2); |
| cout << "v4和v2中的元素进行互换" << endl; |
| printVector(v4); |
| |
| cout << v4.size() << endl; |
| |
| if (v4.empty()) { |
| cout << "空容器" << endl; |
| } |
| else { |
| cout << "非空容器" << endl; |
| } |
| |
| |
| v4.resize(10,-1); |
| printVector(v4); |
| |
| |
4.3 巧用swap
| vector<int> v; |
| for (int i = 0; i < 100000;i++) { |
| v.push_back(i); |
| } |
| cout << "容量" << v.capacity() << "大小" << v.size() << endl; |
| v.resize(3); |
| cout << "容量" << v.capacity() << "大小" << v.size() << endl; |
| |
| |
| vector<int>(v).swap(v); |
| cout << "容量" << v.capacity() << "大小" << v.size() << endl; |
4.4 预留空间reserve函数
| vector<int> v; |
| int *p = NULL; |
| int num = 0; |
| |
| for (int i = 0; i < 100000;i++) { |
| v.push_back(i); |
| |
| if (p != &v[0]) { |
| p = &v[0]; |
| num++; |
| } |
| } |
| cout << num << endl; |
预留空间
| vector<int> v; |
| v.reserve(100000); |
| int *p = NULL; |
| int num = 0; |
| |
| for (int i = 0; i < 100000;i++) { |
| v.push_back(i); |
| |
| if (p != &v[0]) { |
| p = &v[0]; |
| num++; |
| } |
| } |
| cout << num << endl; |
4.5 vector存取元素
| vector<int> v; |
| v.push_back(10); |
| v.push_back(11); |
| v.push_back(12); |
| v.push_back(13); |
| |
| cout << v.front() << endl; |
| cout << v.back() << endl; |
| |
| |
| v.insert(v.begin(), 10000); |
| |
| |
| v.pop_back(); |
| printVector(v); |
| |
| |
| v.erase(v.begin()); |
| |
| v.erase(v.begin(),v.end()); |
| if (v.empty()) { |
| cout << "空的容器" << endl; |
| } |
| |
| |
| v.clear(); |
4.6 逆序遍历
| |
| for (vector<int>::reverse_iterator r = v.rbegin(); r != v.rend();r++) { |
| cout << *r << " "; |
| } |
| cout << endl; |
5 deque容器
deque头插效率更高。
Deque没有容量的概念的,是动态分段空间组成。
原理图:

5.1 常用API
三种迭代器
| void printDeque(const deque<int> &d) { |
| |
| |
| |
| for (deque<int> ::const_iterator begin = d.begin(); begin != d.end(); begin ++) { |
| |
| cout << *begin << " "; |
| } |
构造函数跟vector类似。
| deque<int> d; |
| d.push_back(10); |
| d.push_back(20); |
| d.push_back(30); |
| d.push_back(100); |
| printDeque(d); |
| |
| deque<int> d2(d.begin(),d.end()); |
| d2.push_back(10000); |
| printDeque(d2); |
| |
| |
| d2.swap(d); |
| printDeque(d); |
| |
| if (d2.empty()) { |
| cout << "为空" << endl; |
| } |
| else { |
| cout << "不为空" << endl; |
| } |
| |
| |
| cout << d.front() << endl; |
| cout << d.back() << endl; |
| |
| |
| deque<int> d2(10,1); |
| d.insert(d.begin(), 10); |
| d.insert(d.begin(), d2.begin(), d2.end()); |
| 排序:#include <algorithm> |
| deque<int> d; |
| d.push_back(1); |
| d.push_back(20); |
| d.push_back(12); |
| d.push_back(3); |
| |
| |
| sort(d.begin(),d.end()); |
| |
| sort(d.begin(), d.end(), myCampare); |
| |
| printDeque(d); |
| |
| |
| 随机数讲解: |
| 导入头文件: #include <ctime> |
| srand((unsigned int) time(NULL)); |
| cout << "随机数:" << rand() << endl; |
6 栈容器
| 导入头文件 #include <stack> |
| 压栈:push(ele) |
| 栈大小:size() |
| 返回栈顶元素:top() |
| |
| cout << "栈顶元素为:" << s.top() << endl; |
| |
| s.pop(); |
7 队列
| 导入头文件 |
| #include <queue> |
| queue<int> q; |
| q.push(1); |
| q.push(2); |
| q.push(3); |
| q.push(4); |
| |
| cout << "最后一个元素" << q.back() << endl; |
| cout << "第一个元素" << q.front() << endl; |
| |
| while (q.size() != 0) |
| { |
| cout << q.front() << endl; |
| q.pop(); |
| } |
| cout <<"队列的长度="<< q.size() << endl; |
8 list容器
list容器(上)
list是基于(双向循环)链表的数据结构,vector是线性结构的.
| list<int> ls1(10,10); |
| list<int> ls2(ls1.begin(),ls1.end()); |
| |
| printList(ls1); |
| |
| ls2.push_back(11); |
| for (list<int>::reverse_iterator rbegin = ls2.rbegin(); rbegin != ls2.rend();rbegin ++) { |
| cout << *rbegin << " "; |
| } |
| cout << endl; |
list 不支持随机访问。只能每次向后访问一个元素。
| list<int> l3; |
| l3.push_back(10); |
| l3.push_back(20); |
| l3.push_back(30); |
| l3.push_back(40); |
| |
| l3.push_front(1000); |
| |
| l3.pop_front(); |
| l3.pop_back(); |
| |
| |
| l3.remove(10); |
| printList(l3); |
| |
| |
| list<int > L4; |
| L4.assign(l3.begin(),l3.end()); |
| printList(L4); |
list容器(下)
list翻转排序
| bool ageCompare(Person &p1,Person &p2) { |
| return p1.m_age < p2.m_age; |
| } |
| class Person; |
| void printPersonList(list<Person> &p) { |
| for (const Person p1:p) { |
| cout << p1.m_name << ":" << p1.m_age << " "; |
| } |
| cout << endl; |
| } |
| |
| |
| list<Person> p; |
| Person p1("孙悟空",500); |
| Person p2("猪八戒",30); |
| Person p3("唐僧",23); |
| Person p4("沙僧",300); |
| |
| p.push_back(p1); |
| p.push_back(p2); |
| p.push_back(p3); |
| p.push_back(p4); |
| |
| |
| p.sort(ageCompare); |
| printPersonList(p); |
8.1 删除操作:
| |
| class Person { |
| public : |
| Person(string name,int age,int height) { |
| this->m_name = name; |
| this->m_age = age; |
| this->m_Height = height; |
| } |
| |
| |
| bool operator==(const Person &p) { |
| if (this->m_name == p.m_name && this->m_age == p.m_age && this->m_Height == p.m_Height) { |
| return true; |
| } |
| return false; |
| } |
| |
| string m_name; |
| int m_age; |
| int m_Height; |
| }; |
| |
| |
| p.remove(p6); |
| printPersonList(p); |
9 set容器(加入的元素自动排序)
multiset允许插入重复的值,set和multiset底层都是采用红黑树数据结构。
set容器是关联式容器,自动按照顺序加入容器。(自动排序)
set容器不能插入重复的值。
| set<int> s; |
| |
| s.insert(1); |
| s.insert(13); |
| s.insert(7); |
| s.insert(5); |
| s.insert(9); |
| s.insert(11); |
| |
| printSet(s); |
| |
| if (s.empty()) { |
| cout << "空的容器!" << endl; |
| } |
| else { |
| cout << "容器的大小:" << s.size() << endl; |
| } |
| |
| |
| s.erase(s.begin()); |
| s.erase(11); |
| printSet(s) |
查找操作:
| set<int> s1; |
| s1.insert(3); |
| s1.insert(5); |
| s1.insert(8); |
| s1.insert(6); |
| set<int>::iterator pos = s1.find(5); |
| if (pos != s1.end()) { |
| cout << "找到,值为" << *pos << endl; |
| } |
| else { |
| cout << "没找到" << endl; |
| } |
| |
| |
| cout <<"key值个数:" <<s1.count(8) << endl; |
| |
| cout << s1.count(1) << endl; |
| |
| set<int>::iterator it1 = s1.lower_bound(1); |
| set<int>::iterator it2 = s1.upper_bound(6); |
| cout << *it1 << "\t" << *it2 << endl; |
| |
| |
| |
| pair<set<int>::iterator,set<int>::iterator> ret= s1.equal_range(3); |
10 pair对组的创建方式
| |
| pair<string, int> p = make_pair(string("张三"),34); |
| cout <<"姓名:" << p.first << endl; |
| cout << "年龄:" << p.second << endl; |
10.1 set容器是否可以插入成功判断
| set<int> s; |
| pair<set<int>::iterator, bool> p; |
| p= s.insert(4); |
| cout << "插入是否成功=" << p.second << endl; |
| p = s.insert(4); |
| cout << "插入是否成功=" << p.second << endl; |
10.2 set容器排序(指定set的排序规则)
| |
| |
| class myCompare { |
| public: |
| |
| bool operator()(int v1,int v2) { |
| return v1 > v2; |
| } |
| }; |
| |
| |
| |
| for (set<int, myCompare>::iterator start = s1.begin(); start != s1.end();start ++) { |
| cout << *start << " "; |
| } |
| cout << endl; |
11 set容器插入自定义数据类型
插入自定义数据时,需要指定排序规则。
| class myComparePerson { |
| public: |
| bool operator()(const Person &p1,const Person &p2) { |
| if (p1.m_age > p2.m_age) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| }; |
| void test06() { |
| set<Person,myComparePerson> s1; |
| Person p1("张三",12); |
| Person p2("李四", 22); |
| Person p3("王五", 42); |
| Person p4("赵六", 32); |
| |
| s1.insert(p1); |
| s1.insert(p2); |
| s1.insert(p3); |
| s1.insert(p4); |
| |
| |
| for (set<Person, myComparePerson>::iterator begin = s1.begin(); begin != s1.end();begin ++) { |
| cout << " 姓名:" << begin->m_name << " 年龄:" << begin->m_age <<" "; |
| } |
| cout << endl; |
| } |
7 map/multimap容器
所有元素都会根据元素的键值进行排序。Map所有元素都是pair,第一个元素视为键值,第二个元素视为实值。不允许有两个相同的key值。
| map<int, int> m; |
| |
| |
| m.insert(pair<int,int>(1,10)); |
| |
| m.insert(make_pair(2,10)); |
| |
| |
| m.insert(map<int, int>::value_type(3, 10)); |
| |
| m[4] = 100; |
| |
| for (map<int, int>::iterator begin = m.begin(); begin != m.end(); begin ++) { |
| cout << "key=" << begin->first << " value=" << begin->second << endl; |
| } |
| |
| |
| if (m.empty()) { |
| cout << "为空" << endl; |
| } |
| else { |
| cout << "非空" << endl; |
| } |
| |
| |
| map<int, int>::iterator it = m.find(5); |
| if (it != m.end()) { |
| cout << "找到"<<it->second << endl; |
| } |
| else { |
| cout << "没有找到" << endl; |
| } |
| |
| |
| |
| map<int, int> ::iterator ret = m.lower_bound(3); |
| if (ret != m.end()) { |
| cout << ret->first << " " << ret->second << endl; |
| } |
| |
| ret = m.upper_bound(3); |
| if (ret != m.end()) { |
| cout << ret->first << " " << ret->second << endl; |
| } |
| |
| |
| |
| |
| pair<map<int,int>::iterator, map<int, int>::iterator> ret2 = m.equal_range(3); |
| if (ret2.first != m.end()) { |
| cout << "查找到equal_range中的lower_bound" << ret2.first->first << " " |
| << ret2.first->second |
| <<endl; |
| } |
| if (ret2.second != m.end()) { |
| cout << "查找到equal_range中的upper_bound" << ret2.second->first << " " |
| << ret2.second->second << endl; |
| } |
| |
| 指定排序规则 |
| class myCompare { |
| public: |
| bool operator()(int v1, int v2) { |
| return v1 > v2; |
| } |
| }; |
| |
| |
| void test02() { |
| map<int, int, myCompare> m; |
| |
| m.insert(pair<int, int>(1, 10)); |
| m.insert(pair<int, int>(4, 40)); |
| m.insert(pair<int, int>(2, 80)); |
| |
| m.insert(make_pair(3, 11)); |
| m.insert(map<int, int>::value_type(5, 15)); |
| |
| for (map<int, int, myCompare>::iterator begin = m.begin(); begin != m.end(); begin++) { |
| cout << "key=" << begin->first << " value=" << begin->second << endl; |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?