【C++入门精讲16】 STL 四大核心容器实战教程(vector 缩容 /deque/list/map)
前言本篇文章承接 C IO 流与 STL 基础内容专注讲解STL 高频进阶容器包含 vector 容器缩容操作、deque 双端队列、list 双向链表、map 有序关联容器四大核心模块同时补充仿函数、lambda 表达式、pair 键值对必备知识点。 所有代码100% 保留你原始的代码与注释无任何修改每个模块都配套「核心知识点提取 完整代码示例 补充说明」零基础可直接编译运行完美适配 CSDN 发布、学习笔记、面试复习。一、vector 容器高级用法shrink_to_fit () 容量收缩核心知识点提取vector 基础特性基于连续内存空间数组实现的顺序表容器size () 与 capacity () 区别size()容器中实际存储的元素个数capacity()容器预先分配的总内存容量容量 ≥ 元素个数erase () 删除特性删除元素只会减少size不会改变容量、不会释放内存shrink_to_fit () 核心作用强制收缩容器容量使capacity size释放多余空闲内存优化程序空间占用适用场景容器数据固定、不再扩容时使用。代码示例/* 1.字符串流 sstream 针对string 类对象进行操作 2. 字符缓冲流 strstream 操作目标是 char * istrstream ostrstream strstream 3. STL组成以及vector 容器 STL : 标准模板库 组成容器算法迭代器适配器算法 vector容器顺序表连续空间 数组 */ #includeiostream using namespace std; #if 0 #includevector int main() { vectorint v{ 1,2,5,8,9,10,7,6 }; coutv.size() v.capacity() endl; v.erase(v.begin(),v.begin()4);//删除前四个元素 cout v.size() v.capacity() endl; //让容器的容量与元素的个数保持一致v.shrink_to_fit(); //即将多余的容量删除 v.shrink_to_fit(); cout v.size() v.capacity() endl; } #endif二、deque 双端队列容器详解核心知识点提取底层结构由多个连续内存块组成通过_Map中控器管理各内存块起始地址非一整块连续空间核心优势支持队头、队尾高效插入 / 删除时间复杂度 O (1)关键特性无 capacity () 容量函数内存由容器自动管理无需手动扩容常用 API增push_back/push_front/emplace_back/emplace_front/insert删pop_back/pop_front/erase/clear查front()获取队首元素、back()获取队尾元素遍历方式迭代器遍历、范围 for 遍历、重载流运算符遍历。代码示例#if 0 //一deque双端队列 由多个连续空间组成通过_Map少量连续空间存储不同连续空间的起始位置 #include deque templateclass T ostream operator(ostream os, const dequeT d) { auto it d.begin(); while (it ! d.end()) { cout *it ; it; } cout endl; return cout; } auto find_deque(dequeint deq, int item) { for (auto it deq.begin(); it ! deq.end(); it) { if (*it item) { return it; } } } int main() { dequeint d{ 1,2,3,4,5,6,7,8,9,10 }; //deque的新增 d.push_back(11);//在队尾新增元素 d.push_front(4); d.emplace_back(12);//在队尾新增元素 d.emplace_front(13);//在队头新增元素 d.erase(d.begin(), d.begin() 4);//删除前四个元素 d.insert(d.begin() 2, { 11,21,33 });//在双向循环队列中可以进行批量的插入 d.emplace(d.begin(), 22); coutd.size() endl;//deque是没有容量这个函数的 //deque的遍历可以使用流的遍历即增强for循环 for (auto it d.begin(); it ! d.end(); it) { cout *it ; } cout ----------------------------------------------------------- endl; coutd; //删除元素 //d.clear();//全部删除 d.erase(d.begin(), d.begin() 3); d.erase(d.end() - 3,d.end());//删除最后三个元素 //可以这么理解从最尾部d.end()开始往队列头跳一步删除一个跳三步就是删除三个。 cout d; d.pop_back();//删除最后一个元素 d.pop_front();//删除第一个元素 cout d; int v; while (true) { cout 删除的元素; cin v; if (v -1)break; auto it find_deque(d, v); if (it ! d.end()) { d.erase(it); cout 删除成功 endl; } else { cout删除失败 endl; } } //第一个元素 cout d.front() endl; //最后一个元素 coutd.back() endl; return 0; } #endif三、list 双向链表容器 仿函数 /lambda 表达式核心知识点提取底层结构双向循环链表节点内存独立、不连续核心限制不支持随机访问不能使用[]/at()迭代器仅支持/--不支持算术运算专属 APIremove(val)直接删除所有值为 val 的元素sort()链表自带排序算法效率更高reverse()反转链表remove_if(条件)按自定义条件批量删除元素仿函数重载()运算符的类本质是函数对象可作为判断规则 / 过滤器lambda 表达式匿名函数简化仿函数写法快速实现条件判断remove_if 执行流程遍历元素→传入仿函数 /lambda→返回 true 则删除返回 false 则保留。代码示例//二list 列表 双向链表实现由多个节点组成每个节点存储数据以及前后节点的位置 //仿函数是一个类类中重写了operator()重载函数 // 也就是说仿函数 重载了 () 括号运算符的类长得像函数本质是类对象也叫函数对象。 //仿函数类对象可以作为函数调用 class LessFive { private: int whereval; public: LessFive(int val) :whereval(val) {} bool operator() (int item) { return item whereval; } }; //通俗流程 //仿函数 过滤规则 / 过滤器提前定好筛选条件 #if 0 #includelist #includedeque #includefunctional //STL自带的仿函数 int main() { listint list1{ 9,2,1,3,4 }; //新增元素 list1.push_back(20); list1.push_front(12); list1.emplace_front(22); list1.emplace_back(8); list1.insert(list1.begin(), { 10,11 });//可以进行批量插入 //遍历 //[],at(),不允许不支持 for (auto item : list1) { cout item ; }//可以使用增强for循环 cout endl; //删除元素 //list的迭代器不支持 算术运算只支持--这两种形式 //list1.erase(list1.begin(), list1, begin() 3);//error//也就是说不可以一次性一句erase语句进行批量删除 for (int i 0; i 3; i) list1.erase(list1.begin()); list1.remove(3);//删除值为3的元素//额可以直接进行删除 list1.sort(); //从小到大排序 for (int item : list1) { cout item ; } cout endl; //反转链表 list1.reverse(); for (int item : list1) { cout item ; } cout endl; //支持排序 //默认 从小到大排序less list1.sort(greater());//greater()是STL自带的仿函数表示从大到小排序 for (int item : list1) { cout item ; } cout endl; list1.sort(less());//从小到大排序 for (int item : list1) { cout item ; } cout endl; //思考 删除list1列表中所有小于5的元素 /*for (int item : list1) { if (item 5) { cout item ; } else break; }*/ list1.remove_if(LessFive(5));//使用仿函数进行删除,删除所有小于5的元素 for (int item : list1) { cout item ; } cout endl; list1.remove_if([](int item) {return item 5; });//使用lambda表达式进行删除删除所有小于5的元素 for (int item : list1) { cout item ; } cout endl; list1.remove_if(LessFive(8)); //remove_if 逐个遍历容器里每一个元素把元素挨个传给仿函数 //仿函数按规则判断满足条件就返回true //remove_if 收到true就把这个元素删掉返回false就留下 for (int item : list1) { cout item ; } cout endl; return 0; } #endif四、map 有序关联容器红黑树详解核心知识点提取底层结构红黑树平衡二叉搜索树元素按键key自动有序排列存储元素pair键值对格式为pairK, Vfirst对应键keysecond对应值value核心特性键 key 唯一不可重复值 value 可重复排序规则默认按 key升序排列指定greater可实现降序排列pair 创建方式直接赋值、初始化列表、make_pair()函数插入规则insert/emplacekey 已存在则插入失败[key]key 存在则修改 valuekey 不存在则插入新键值对遍历方式迭代器遍历、范围 for 遍历。代码示例#includemap //三有序关联容器map(红黑树)//键值不可以重复 #if 0 //3.1 map容器中存储的元素项 pair键值对 //pairK,V键的类型V值类型 //K的值 fist //V的值 second int main() { //创建键值对的三种方式 pairint, int p1; p1.first 1001;//PID p1.second 99;//socre //键值对的元素访问 coutK:p1.first, V:p1.secondendl; pairint, stringp2{ 1001,dision }; coutK:p2.first, V:p2.secondendl; pairint, string p3 make_pair(1002, lucy); return 0; } #endif int main() { //map容器元素是键值对即pair //mapK,V K的类型V的类型,默认按照k值从小到大排序 mapint, string m1{ {1,A}, {2,B},{5,C},{4,D} }; //遍历 auto it m1.begin(); //迭代器表示元素的位置 while (it ! m1.end()) { coutK:it-first, V:it-secondendl; it; } mapint, string,greater m2{ {1,A}, {2,B},{5,C},{4,D} }; auto it2 m2.begin(); //迭代器表示元素的位置 while (it2 ! m2.end()) { cout K: it2-first , V: it2-second endl; it2; } //新增元素 m1.emplace(6, E); m1.emplace(6, l); m1.emplace(make_pair(10, e)); m1.insert(make_pair(7, F)); m1.insert(pairint, string(7, C)); m1.insert(pairint, string(8, G)); m1[9] H;//中括号里面是键值 //如果k存在则不会插入如果k不存在则插入v则没有要求,也就是v怎么样无所谓 //但是对于这种类似下标访问的方式则有点特殊 m1[1] Mack; // 如果K存在则更新V m1[6] Jack; // 如果K不存在则插入 m1[11] H; cout ----------------------------------------------------------- endl; for (auto item : m1) { cout K: item.first , V: item.second endl; } }五、四种容器的区别对比维度vector动态数组deque双端队列list双向链表map有序关联容器底层数据结构单块连续内存的动态数组多段连续内存块 中控器_Map管理双向循环链表节点独立存储红黑树平衡二叉搜索树内存连续性整块内存完全连续分段连续整体非连续内存完全不连续内存完全不连续随机访问效率O (1)支持[]/at()直接访问O (1)支持[]/at()直接访问O (n)不支持随机访问仅能迭代遍历O (logn)通过 key 快速查找不支持下标随机访问插入 / 删除效率尾部插入 / 删除 O (1)中间 / 头部插入 / 删除 O (n)需移动元素头部 / 尾部插入 / 删除 O (1)中间插入 / 删除 O (n)任意位置插入 / 删除 O (1)仅需修改节点指针插入 / 删除 O (logn)需维护红黑树平衡排序支持需调用std::sort算法排序需调用std::sort算法排序自带sort()成员函数排序效率更高本身按键key自动有序无需手动排序核心优势随机访问速度快、内存连续、缓存友好、API 简单易用头尾增删效率极高、无容量概念、自动管理内存任意位置增删效率高、无需移动元素、迭代器稳定键值对存储、key 唯一、自动有序、查找效率高核心劣势中间 / 头部增删效率低、扩容有性能开销中间增删效率低、内存分段、缓存友好性不如 vector不支持随机访问、内存开销大每个节点需存前后指针内存开销大、插入删除有平衡树的性能开销适用场景大部分通用场景、数据量固定、随机访问需求多、极少中间增删的业务头尾频繁增删的场景如队列、栈、滑动窗口、无需随机访问的业务频繁在中间位置插入 / 删除元素的场景、无需随机访问的业务需要键值对映射、快速按 key 查找、要求数据有序的场景如字典、缓存、索引核心高频 APIpush_back/emplace_back/erase/clear/reserve/shrink_to_fitpush_back/push_front/pop_back/pop_front/erase/insertpush_back/push_front/remove/remove_if/sort/reverseinsert/emplace/[]/find/erase/clear六、总结本文完整讲解了 C STL 四大核心容器的实战用法所有代码严格保留原始内容知识点覆盖全面vector连续内存支持随机访问shrink_to_fit实现容量收缩deque双端队列头尾增删高效无容量概念list双向链表任意位置增删高效配合仿函数 /lambda 实现条件删除map有序键值对容器key 唯一基于红黑树实现查找效率极高。本文为纯手打原创代码笔记适合 C 初学者、开发者学习使用欢迎点赞收藏转发