品牌宣传网站做网站广告公司
2026/5/21 7:16:56 网站建设 项目流程
品牌宣传网站,做网站广告公司,导航网站优化,做网站需要什么语言一文搞懂C之容器篇 C STL#xff08;标准模板库#xff09;的核心价值之一就是提供了丰富的容器——即“存储数据的通用结构”#xff0c;能帮我们快速实现数据的存储、访问、插入、删除等操作#xff0c;无需重复造轮子。本文将C常用容器按“功能分类”梳理#xff0c;从…一文搞懂C之容器篇C STL标准模板库的核心价值之一就是提供了丰富的容器——即“存储数据的通用结构”能帮我们快速实现数据的存储、访问、插入、删除等操作无需重复造轮子。本文将C常用容器按“功能分类”梳理从底层实现到实际用法层层拆解结合代码示例和选型建议让你彻底搞懂“什么时候用什么容器”。先明确核心概念C容器本质是“模板类”支持存储不同类型的数据如int、string、自定义结构体分为三大类序列式容器按“插入顺序”存储数据元素有明确的位置关系如数组、链表关联式容器按“键key”排序存储数据支持快速查找如字典、有序集合容器适配器基于其他容器封装的“特殊功能容器”如栈、队列不直接存储数据。一、序列式容器按顺序存储核心是“位置”序列式容器的核心是“元素的插入顺序存储顺序”访问时依赖“位置索引”或“迭代器遍历”适合需要保持数据顺序的场景。常用的有4个vector、list、deque、array。1. vector动态数组最常用核心特性底层实现动态数组连续内存空间扩容时会分配新的更大内存拷贝旧数据后释放旧内存访问效率随机访问极快O(1)通过索引直接访问插入/删除尾部插入/删除极快O(1)中间/头部插入/删除慢O(n)需要移动后续元素内存特点预分配内存capacity size避免频繁扩容支持预留内存reserve优化性能。C代码示例常用操作#includeiostream#includevectorusingnamespacestd;intmain(){// 1. 初始化vectorintvec1;// 空vectorvectorintvec2(5,10);// 5个元素每个都是10vectorintvec3{1,2,3,4,5};// 初始化列表C11vectorintvec4(vec3.begin(),vec3.end());// 用迭代器拷贝// 2. 插入元素vec1.push_back(6);// 尾部插入推荐O(1)vec1.emplace_back(7);// 尾部构造插入更高效避免拷贝C11vec3.insert(vec3.begin()2,99);// 中间插入在索引2处插入99O(n)// 3. 访问元素coutvec3[2]endl;// 索引访问无越界检查coutvec3.at(2)endl;// at访问有越界检查抛出异常coutvec3.front()endl;// 访问第一个元素coutvec3.back()endl;// 访问最后一个元素// 4. 遍历// 方式1范围forC11最简洁for(intval:vec3){coutval ;}coutendl;// 方式2迭代器for(vectorint::iterator itvec3.begin();it!vec3.end();it){cout*it ;}coutendl;// 5. 删除元素vec3.pop_back();// 尾部删除O(1)vec3.erase(vec3.begin()2);// 中间删除删除索引2的元素O(n)vec3.clear();// 清空所有元素size0capacity不变// 6. 内存优化vec3.reserve(10);// 预留10个元素的内存避免频繁扩容vec3.shrink_to_fit();// 释放多余内存让capacitysizeC11return0;}适用场景适合“频繁随机访问、尾部插入/删除”的场景如存储检测框坐标、传感器采集的时序数据、需要快速索引的数据列表。工程中最常用的容器优先考虑vector。2. list双向链表核心特性底层实现双向链表非连续内存每个节点存储数据和前后指针访问效率随机访问极慢O(n)必须遍历查找插入/删除任意位置插入/删除极快O(1)只需修改节点指针无需移动元素内存特点每个节点额外存储两个指针内存开销比vector大无扩容问题。关键操作示例区别于vector#includelistusingnamespacestd;intmain(){listintlst{1,2,3,4};// 1. 任意位置插入/删除高效autoitlst.begin();advance(it,2);// 迭代器移动到第3个元素只能通过advance移动无索引lst.insert(it,99);// 在位置2插入99O(1)lst.erase(it);// 删除当前迭代器指向的元素O(1)// 2. 链表特有操作lst.push_front(0);// 头部插入O(1)vector无此操作lst.pop_front();// 头部删除O(1)vector无此操作lst.reverse();// 反转链表O(n)lst.sort();// 排序O(nlogn)底层是归并排序lst.unique();// 去重需先排序O(n)// 3. 遍历只能用迭代器或范围for无索引for(intval:lst){coutval ;}return0;}适用场景适合“频繁在任意位置插入/删除”的场景如需要频繁调整顺序的任务列表、数据频繁增删的缓存如LRU缓存的底层可基于list实现。避免用于需要随机访问的场景。3. deque双端队列核心特性底层实现“分段连续内存”多个连续内存块用指针数组管理访问效率随机访问较快O(1)但比vector慢需要先定位内存块插入/删除头部和尾部插入/删除极快O(1)中间插入/删除慢O(n)内存特点无扩容拷贝问题新增内存块即可内存利用率比vector高。适用场景适合“频繁头部尾部插入/删除”的场景如队列的底层实现、滑动窗口算法的数据存储。日常使用频率低于vector和list只有需要“双端快速操作”时才考虑。4. array固定大小数组C11核心特性底层实现静态数组连续内存大小编译时确定不可修改访问效率随机访问最快O(1)无动态扩容开销插入/删除不支持动态插入/删除大小固定对比普通数组比C风格数组int arr[5]更安全支持边界检查、迭代器更易用。代码示例#includearrayusingnamespacestd;intmain(){arrayint,5arr{1,2,3,4,5};// 大小5固定编译时确定arr[0]10;coutarr.at(2)endl;// 边界检查coutarr.size()endl;// 大小固定为5// 遍历for(intval:arr){coutval ;}return0;}适用场景适合“数据量固定、需要极致访问效率”的场景如存储固定长度的配置参数、嵌入式开发中的固定大小缓冲区。不适合数据量动态变化的场景。二、关联式容器按key排序核心是“快速查找”关联式容器的核心是“键key”——元素按key的大小排序存储支持通过key快速查找O(logn)无需遍历。分为“有序关联式”和“无序关联式”两类有序的底层是红黑树平衡二叉树无序的底层是哈希表。1. 有序关联式容器set/multiset/map/multimap共同特性底层是红黑树元素按key升序排序默认支持自定义排序规则查找、插入、删除的时间复杂度都是O(logn)。1set有序唯一集合核心特点存储“唯一的key”不允许重复元素按key排序本质keyvalue存储的元素就是key本身常用操作插入、删除、查找按key、去重、排序。#includesetusingnamespacestd;intmain(){// 1. 初始化默认升序setints{3,1,4,1,2};// 自动去重排序结果1,2,3,4// 降序排序自定义比较规则setint,greaterints_desc{3,1,4,2};// 结果4,3,2,1// 2. 插入s.insert(5);// 插入5O(logn)若插入重复元素无效果// 3. 查找autoits.find(3);// 按key查找返回迭代器O(logn)if(it!s.end()){cout找到*itendl;}// 4. 统计元素个数因为唯一只能是0或1couts.count(1)endl;// 输出1// 5. 删除s.erase(2);// 按key删除O(logn)s.erase(it);// 按迭代器删除O(1)// 6. 遍历有序for(intval:s){coutval ;// 输出1 3 4 5}return0;}2multiset有序可重复集合核心区别于set允许重复keycount()方法返回元素的重复次数erase(key)会删除所有重复元素。#includesetusingnamespacestd;intmain(){multisetintms{3,1,4,1,2,1};// 排序后1,1,1,2,3,4coutms.count(1)endl;// 输出3重复3次// 删除所有key1的元素ms.erase(1);// 只删除一个key2的元素先find找到迭代器autoitms.find(2);if(it!ms.end()){ms.erase(it);}return0;}3map有序唯一键值对核心特点存储“key-value键值对”key唯一且有序本质通过key快速查找valueO(logn)类似字典常用操作插入键值对、按key查找value、遍历键值对。#includemap#includestringusingnamespacestd;intmain(){// 1. 初始化默认key升序mapstring,intdict{{apple,1},{banana,2},{orange,3}};// 2. 插入键值对dict.insert(pairstring,int(grape,4));// 方式1pairdict.emplace(pear,5);// 方式2emplace更高效C11dict[watermelon]6;// 方式3[]运算符不存在则插入存在则修改// 3. 查找value// 方式1find推荐先判断是否存在autoitdict.find(banana);if(it!dict.end()){coutbanana: it-secondendl;// it-first是keyit-second是value}// 方式2[]运算符注意不存在则插入默认值0coutgrape: dict[grape]endl;// 4. 遍历键值对for(auto[key,val]:dict){// C17结构化绑定简洁coutkey: valendl;}// 兼容旧版本// for (mapstring, int::iterator it dict.begin(); it ! dict.end(); it) {// cout it-first : it-second endl;// }// 5. 删除dict.erase(orange);// 按key删除O(logn)dict.erase(it);// 按迭代器删除O(1)return0;}4multimap有序可重复键值对核心区别于map允许重复key通过equal_range()获取所有相同key的键值对。#includemapusingnamespacestd;intmain(){multimapstring,intmmap;mmap.emplace(apple,1);mmap.emplace(apple,2);mmap.emplace(banana,3);// 获取所有keyapple的键值对autorangemmap.equal_range(apple);for(autoitrange.first;it!range.second;it){coutit-first: it-secondendl;// 输出apple:1、apple:2}return0;}2. 无序关联式容器unordered_set/unordered_multiset/unordered_map/unordered_multimapC11共同特性底层是哈希表hash table元素无序查找、插入、删除的平均时间复杂度是O(1)最坏O(n)哈希冲突严重时比有序关联式容器更快但无序。用法几乎和有序版本一致核心区别无序不支持排序遍历结果是随机的不支持自定义排序规则但支持自定义哈希函数不支持lower_bound()、upper_bound()等有序相关的迭代器操作效率更高平均O(1)的操作效率适合高频查找场景。核心示例unordered_map#includeunordered_mapusingnamespacestd;intmain(){unordered_mapstring,intu_dict{{apple,1},{banana,2}};// 插入/查找/删除用法和map一致但无序u_dict[grape]3;autoitu_dict.find(banana);if(it!u_dict.end()){coutit-secondendl;}// 遍历结果随机不排序for(auto[key,val]:u_dict){coutkey: valendl;// 可能输出banana:2、apple:1、grape:3}return0;}有序vs无序关联式容器选型需要有序唯一用set/map需要有序可重复用multiset/multimap不需要有序追求高效查找用unordered_set/unordered_map工程中更常用自定义类型作为key有序容器需要重载运算符无序容器需要自定义哈希函数和运算符。三、容器适配器封装已有容器核心是“特殊功能”容器适配器不直接存储数据而是“封装”其他容器如vector、deque提供特定的操作接口如栈的先进后出。常用的有3个stack、queue、priority_queue。1. stack栈先进后出LIFO底层默认容器deque可指定为vector或list核心操作push入栈、pop出栈、top访问栈顶不支持迭代器遍历只能访问栈顶。#includestackusingnamespacestd;intmain(){stackintst;// 默认deque为底层容器// stackint, vectorint st; // 指定vector为底层容器st.push(1);st.push(2);st.push(3);coutst.top()endl;// 访问栈顶3st.pop();// 出栈删除3coutst.top()endl;// 2coutst.size()endl;// 2coutst.empty()endl;// falsereturn0;}2. queue队列先进先出FIFO底层默认容器deque核心操作push入队、pop出队、front访问队首、back访问队尾不支持迭代器遍历。#includequeueusingnamespacestd;intmain(){queueintq;q.push(1);q.push(2);q.push(3);coutq.front()endl;// 队首1coutq.back()endl;// 队尾3q.pop();// 出队删除1coutq.front()endl;// 2return0;}3. priority_queue优先队列大顶堆/小顶堆底层默认容器vector基于堆结构实现核心特性每次出队的是“优先级最高”的元素默认大顶堆最大元素优先核心操作push入队、pop出队、top访问优先级最高元素。#includequeueusingnamespacestd;intmain(){// 1. 默认大顶堆最大元素优先priority_queueintpq_max;pq_max.push(3);pq_max.push(1);pq_max.push(4);coutpq_max.top()endl;// 4最大pq_max.pop();coutpq_max.top()endl;// 3// 2. 小顶堆最小元素优先自定义比较规则priority_queueint,vectorint,greaterintpq_min;pq_min.push(3);pq_min.push(1);pq_min.push(4);coutpq_min.top()endl;// 1最小pq_min.pop();coutpq_min.top()endl;// 3return0;}适用场景stack函数调用栈、表达式求值、回溯算法如迷宫求解queue任务队列、消息队列、广度优先搜索BFSpriority_queueTopK问题如取前10个置信度最高的检测框、贪心算法、堆排序。四、C容器核心选型指南工程实战必备容器选型的核心是“匹配场景的操作需求”优先考虑“效率易用性”以下是高频场景的选型建议1. 优先选vector的场景• 频繁随机访问用索引访问• 频繁尾部插入/删除• 数据量动态变化且无频繁中间增删• 不确定用什么容器时先试vector兼容性最好工程最常用。2. 选list的场景• 频繁在任意位置插入/删除• 不需要随机访问• 数据量动态变化且增删位置不固定如任务列表。3. 选关联式容器的场景• 需快速查找按key优先unordered_map/unordered_setO(1)• 需有序查找选map/setO(logn)• 需键值对存储选map/unordered_map• 需去重选set/unordered_set• 需重复key选multiset/multimap。4. 选容器适配器的场景• 先进后出stack• 先进先出queue• 优先级排序priority_queue。5. 避坑指南vector迭代器失效扩容、中间插入/删除时迭代器会失效避免保存过期迭代器unordered容器的哈希冲突自定义类型作为key时需确保哈希函数设计合理避免冲突导致效率下降容器的拷贝开销大容器拷贝时用引用或移动语义moveC11避免浅拷贝内存管理vector用reserve()预留内存避免频繁扩容不用的容器及时clear()或用局部变量自动释放。五、总结C容器的核心是“按需选择”序列式容器侧重“顺序存储”适合按位置操作关联式容器侧重“key查找”适合快速检索容器适配器侧重“特殊功能”适合特定操作规则。工程中最常用的容器组合是vector基础存储unordered_map快速查找priority_queueTopK问题。掌握这些容器的核心特性和用法就能覆盖80%以上的开发场景。最后记住不要过度追求“最复杂的容器”简单的容器如vector往往更易维护、兼容性更好。只有当简单容器无法满足效率需求时再考虑更复杂的容器如list、unordered_map。注文档部分内容可能由 AI 生成

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询