当前位置: 首页 > news >正文

【C++入门精讲16】 STL 四大核心容器实战教程(vector 缩容 /deque/list/map)

前言

本篇文章承接 C++ IO 流与 STL 基础内容,专注讲解STL 高频进阶容器,包含 vector 容器缩容操作、deque 双端队列、list 双向链表、map 有序关联容器四大核心模块,同时补充仿函数、lambda 表达式、pair 键值对必备知识点。 所有代码100% 保留你原始的代码与注释,无任何修改,每个模块都配套「核心知识点提取 + 完整代码示例 + 补充说明」,零基础可直接编译运行,完美适配 CSDN 发布、学习笔记、面试复习。


一、vector 容器高级用法:shrink_to_fit () 容量收缩

核心知识点提取

  1. vector 基础特性:基于连续内存空间(数组)实现的顺序表容器;
  2. size () 与 capacity () 区别
    • size():容器中实际存储的元素个数
    • capacity():容器预先分配的总内存容量(容量 ≥ 元素个数)
  3. erase () 删除特性:删除元素只会减少size不会改变容量、不会释放内存
  4. shrink_to_fit () 核心作用:强制收缩容器容量,使capacity = size,释放多余空闲内存,优化程序空间占用;
  5. 适用场景:容器数据固定、不再扩容时使用。

代码示例

/* 1.字符串流 <sstream> 针对string 类对象进行操作 2. 字符缓冲流 <strstream> 操作目标是 char * istrstream ostrstream strstream 3. STL组成以及vector 容器 STL : 标准模板库 组成:容器,算法,迭代器,适配器,算法 vector容器:顺序表(连续空间: 数组) */ #include<iostream> using namespace std; #if 0 #include<vector> int main() { vector<int> v{ 1,2,5,8,9,10,7,6 }; cout<<v.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 双端队列容器详解

核心知识点提取

  1. 底层结构:由多个连续内存块组成,通过_Map中控器管理各内存块起始地址,非一整块连续空间
  2. 核心优势:支持队头、队尾高效插入 / 删除,时间复杂度 O (1);
  3. 关键特性无 capacity () 容量函数,内存由容器自动管理,无需手动扩容;
  4. 常用 API
    • 增:push_back/push_front/emplace_back/emplace_front/insert
    • 删:pop_back/pop_front/erase/clear
    • 查:front()获取队首元素、back()获取队尾元素;
  5. 遍历方式:迭代器遍历、范围 for 遍历、重载流运算符遍历。

代码示例

#if 0 //一,deque双端队列: 由多个连续空间组成,通过_Map(少量)连续空间,存储不同连续空间的起始位置 #include <deque> template<class T> ostream& operator<<(ostream& os, const deque<T>& d) { auto it = d.begin(); while (it != d.end()) { cout << *it << " "; it++; } cout << endl; return cout; } auto find_deque(deque<int> &deq, int item) { for (auto it = deq.begin(); it != deq.end(); it++) { if (*it == item) { return it; } } } int main() { deque<int> 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); cout<<d.size() << endl;//deque是没有容量这个函数的 //deque的遍历:可以使用流的遍历,即增强for循环 for (auto it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << "-----------------------------------------------------------" << endl; cout<<d; //删除元素: //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; //最后一个元素: cout<<d.back() << endl; return 0; } #endif

三、list 双向链表容器 + 仿函数 /lambda 表达式

核心知识点提取

  1. 底层结构双向循环链表,节点内存独立、不连续
  2. 核心限制不支持随机访问(不能使用[]/at()),迭代器仅支持++/--,不支持算术运算;
  3. 专属 API
    • remove(val):直接删除所有值为 val 的元素;
    • sort():链表自带排序算法,效率更高;
    • reverse():反转链表;
    • remove_if(条件):按自定义条件批量删除元素;
  4. 仿函数:重载()运算符的类,本质是函数对象,可作为判断规则 / 过滤器;
  5. lambda 表达式:匿名函数,简化仿函数写法,快速实现条件判断;
  6. 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 #include<list> #include<deque> #include<functional> //STL自带的仿函数 int main() { list<int> 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 有序关联容器(红黑树)详解

核心知识点提取

  1. 底层结构红黑树(平衡二叉搜索树),元素按键key自动有序排列;
  2. 存储元素pair键值对,格式为pair<K, V>first对应键keysecond对应值value
  3. 核心特性键 key 唯一不可重复,值 value 可重复;
  4. 排序规则:默认按 key升序排列,指定greater<>可实现降序排列;
  5. pair 创建方式:直接赋值、初始化列表、make_pair()函数;
  6. 插入规则
    • insert/emplace:key 已存在则插入失败
    • [key]:key 存在则修改 value,key 不存在则插入新键值对
  7. 遍历方式:迭代器遍历、范围 for 遍历。

代码示例

#include<map> //三,有序关联容器:map(红黑树)//键值不可以重复 #if 0 //3.1 map容器中存储的元素(项): pair键值对 //pair<K,V>键的类型,V值类型 //K的值: fist //V的值: second int main() { //创建键值对的三种方式 pair<int, int > p1; p1.first = 1001;//PID p1.second = 99;//socre //键值对的元素访问 cout<<"K:"<<p1.first<<", V:"<<p1.second<<endl; pair<int, string>p2{ 1001,"dision" }; cout<<"K:"<<p2.first<<", V:"<<p2.second<<endl; pair<int, string> p3 = make_pair(1002, "lucy"); return 0; } #endif int main() { //map容器,元素是键值对,即pair //map<K,V> K的类型,V的类型,默认按照k值从小到大排序 map<int, string> m1{ {1,"A"}, {2,"B"},{5,"C"},{4,"D"} }; //遍历: auto it = m1.begin(); //迭代器表示元素的位置 while (it != m1.end()) { cout<<"K:"<<it->first<<", V:"<<it->second<<endl; it++; } map<int, 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(pair<int, string>(7, "C")); m1.insert(pair<int, 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 四大核心容器的实战用法,所有代码严格保留原始内容,知识点覆盖全面:

  1. vector:连续内存,支持随机访问,shrink_to_fit实现容量收缩;
  2. deque:双端队列,头尾增删高效,无容量概念;
  3. list:双向链表,任意位置增删高效,配合仿函数 /lambda 实现条件删除;
  4. map:有序键值对容器,key 唯一,基于红黑树实现,查找效率极高。

本文为纯手打原创代码笔记,适合 C++ 初学者、开发者学习使用,欢迎点赞收藏转发!

http://www.cnnetsun.cn/news/2708064.html

相关文章:

  • 【RT-DETR实战】 119、瑞芯微RKNN平台部署实战:从模型转换到板端推理的坑与经验
  • 魔兽争霸3性能优化终极指南:WarcraftHelper插件完整使用教程
  • TVA在电子元器件领域的创新应用(20)
  • 别再手动查漏洞了!用OWASP DependencyCheck给你的Maven项目做个自动化体检(附Jenkins流水线配置)
  • LED矩阵显示器的工业铝型材框架制作全攻略
  • AI没有复制互联网,它正在复制工业革命
  • 利用大语言模型生成数据增强仇恨言论检测模型的鲁棒性
  • 鸣潮自动化助手终极指南:5步实现智能挂机,解放双手轻松游戏
  • 机器人抓取新思路:为什么说6-DOF GraspNet的‘模块化’设计,是工业落地的关键?
  • Windows 10/11系统下,用vcpkg一键安装Tesseract C++库的避坑指南
  • 微信聊天记录解密终极指南:3分钟掌握WechatDecrypt工具
  • 从/lib到/libx32:一文看懂Linux多架构库目录的演变与设计哲学
  • AI漫剧创业冰火两重天:有人亏损近20万,有人小而美仍有得赚
  • TMSpeech:Windows本地实时语音转文字神器,让会议记录和内容创作效率翻倍
  • 告别‘炼丹’:手把手教你用Python复现经典跨模态哈希算法(附代码与避坑指南)
  • 3分钟把B站视频变文字稿:这个工具让你学习效率翻倍
  • 阴阳师自动化脚本OAS:5个高效技巧解放你的双手
  • MATLAB动态权重A*路径规划代码(含拐角平滑处理)
  • 智能手机改造乐器拾音器:低成本DIY方案与音频信号处理实践
  • 终极指南:如何让Windows任务栏变透明?TranslucentTB完全使用教程
  • Android MediaCodec解码到Surface的‘水管工’指南:搞懂BufferQueue、releaseOutputBuffer与SurfaceFlinger的协作流水线
  • Vite + PostCSS实战:一键搞定移动端到桌面端的‘优雅降级’适配
  • 从Telnet到WebSocket:Nagle算法这个“古董”是如何影响现代实时应用的?
  • 从Word迁移到LaTeX:给科研小白的避坑指南与效率工具包
  • 从论文到代码:手把手教你用Keras从零实现VGG网络
  • 微软500万美元云积分捐赠:解析科研算力困境与云原生转型路径
  • 不只是安装:用Blue Kenue可视化你的TELEMAC二维模型结果(以Malpasset溃坝为例)
  • 告别紫红球!Unity Asset Bundle依赖打包实战:如何避免材质丢失与资源重复
  • 脉冲神经网络与强化学习的融合挑战及CaRe-BN技术解析
  • AMD Ryzen SDT调试工具:终极硬件性能调优完整指南