免费做做网站,网上超市,几十元做网站,如何免费网络营销推广C标准库大全(STL) 1. 容器#xff08;Containers#xff09; *问题类型#xff1a; 序列容器#xff08;std::vector, std::deque, std::list, std::forward_list, std::array, std::string#xff09;#xff1a; 各自的特点、底层实现、优缺点和适用场景#xff1f; 容…C标准库大全(STL) 1. 容器Containers *问题类型 序列容器std::vector, std::deque, std::list, std::forward_list, std::array, std::string 各自的特点、底层实现、优缺点和适用场景 容器特点底层实现优点缺点适用场景std::vector动态数组支持快速随机访问连续内存 三指针数据头/尾/容量尾随机访问 O(1)缓存友好尾部操作高效中间插入/删除 O(n)扩容需数据拷贝随机访问为主尾部增删如数据缓存std::deque双端队列头尾插入高效分段连续数组 中央映射表头尾插入/删除 O(1)支持随机访问 O(1)中间插入 O(n)内存碎片化访问速度略慢于 vector队列/栈需双端操作如任务调度std::list双向链表任意位置插入高效双向链表节点prev/data/next任意位置插入/删除 O(1)无扩容开销随机访问 O(n)内存占用高缓存不友好频繁中间增删如 LRU 缓存std::forward_list单向链表内存更省单向链表节点data/next内存开销极低单指针插入/删除 O(1)仅单向遍历无反向迭代器操作需前驱节点内存敏感场景如嵌入式系统链表std::array固定大小数组编译时确定尺寸栈上分配的 C 风格数组封装零内存开销随机访问 O(1)无动态分配成本大小不可变无动态扩容替代 C 数组如固定尺寸矩阵运算std::string动态字符串支持丰富操作类 vector SSO 优化自动内存管理内置操作find/replace 等性能略低于 char*SSO 有大小限制字符串处理如文本解析/日志拼接 vector 扩容 扩容因子1.5/2倍平衡 均摊 O(1) 时间成本 与 内存碎片问题 1.5 倍释放的内存块可被后续扩容重用例释放 4MB 后1.5 倍扩容 6MB 可重用该内存。2 倍内存重用困难例4MB → 8MB → 16MB释放的 4MB8MB 无法用于 16MB。 deque 随机访问 计算过程元素位置 段起始地址 段内偏移比 vector 多一次地址跳转。 SSO短字符串优化 string 对短字符串通常 ≤15 字符直接在栈存储避免堆分配 std::string s Short; // 栈存储
std::string l Long string over 15 chars; // 堆存储 链表选择指南 需双向遍历 → list仅需单向遍历 省内存 → forward_list高频中间插入 → 优先链表高频随机访问 → 优先 vector/deque。 性能临界场景 超高频操作如金融交易优先 array/vector缓存友好内存敏感如嵌入式优先 forward_list/array。 vector的扩容机制为什么是 2 倍或 1.5 倍 扩容机制 当插入元素超过当前容量时分配新内存原容量的 n 倍拷贝旧数据到新空间释放旧内存。 扩容因子1.5或2倍的原因 均摊时间复杂度 扩容因子需保证插入操作的均摊时间复杂度为 O(1)。数学证明当因子 k 1 时均摊成本为 O(1)。 内存重用 1.5倍旧内存块释放后后续扩容可能重用新旧内存块大小无重叠。 例如释放 sizeM 后新申请 1.5M后续扩容可能使用之前释放的 M 内存。 2倍释放的内存块总和M 2M 4M ...无法被后续更大的块重用如 8M。 折中策略 过小如1.1倍扩容频繁拷贝开销大。过大如3倍内存浪费严重。 主流实现 GCC2倍扩容VS1.5倍扩容。 vector和list的区别 特性vectorlist底层结构动态数组连续内存双向链表非连续内存随机访问O(1)支持下标访问O(n)需遍历头部插入/删除O(n)移动元素O(1)尾部插入/删除均摊 O(1)O(1)中间插入/删除O(n)移动元素O(1)定位后操作内存占用较少仅需存储数据较高每个节点含两个指针缓存友好性高连续内存低内存碎片化扩容开销需重新分配内存和拷贝无扩容动态分配节点 string和char*的区别 特性stringchar*内存管理自动分配/释放RAII手动管理malloc/free安全性防越界自动扩容易缓冲区溢出/内存泄漏功能扩展丰富成员函数find、append等依赖C库函数strcpy、strcat结尾标识可包含 \0长度独立管理以 \0 结尾性能开销略高封装成本极低直接操作内存兼容性C专用兼容C/C 关键结论 优先使用 string安全、便捷适合大多数场景。使用 char*需兼容C或极限性能优化如高频交易系统。 关联容器std::set, std::multiset, , std::map, std::multimap 各自的特点、底层实现红黑树、优缺点和适用场景 容器特点底层实现优点缺点适用场景std::set唯一键集合自动排序红黑树有序遍历查找/插入 O(log n)内存占用高每个节点额外信息需有序唯一键如字典std::multiset键可重复自动排序红黑树支持重复键有序同 set需有序但键可重复如成绩排名std::map键值对键唯一按键排序红黑树按键有序范围查询高效同 set键值映射需有序如学生ID→信息std::multimap键值对键可重复按键排序红黑树支持重复键有序同 set一键多值如作者→著作列表底层实现核心红黑树 特性 自平衡二叉搜索树保证树高 ≈ log n。节点含颜色标记红/黑通过旋转和变色维持平衡。 操作复杂度 查找、插入、删除O(log n)。 额外开销 每个节点存储父/子指针、颜色标记内存占用高于哈希表。 map和unordered_map的区别 特性std::mapstd::unordered_map底层实现红黑树平衡二叉搜索树哈希表桶数组 链表/红黑树元素顺序按键有序升序无序取决于哈希函数查找复杂度O(log n)平均 O(1)最坏 O(n)内存占用较低树结构较高预分配桶 链表指针键类型要求需支持 或自定义比较器需支持哈希函数和 比较适用场景需有序访问/范围查询只需快速查找如缓存/计数器关键区别 顺序需求 map保证顺序遍历时按键升序。unordered_map元素顺序不可控依赖哈希函数。 性能权衡 unordered_map平均 O(1) 查找但哈希冲突时退化最坏 O(n)。map稳定 O(log n)无性能波动。 内存敏感场景 优先 map无预分配桶开销。 C11 优化 unordered_map 桶内改用红黑树如 GCC最坏复杂度优化至 O(log n)。 如何自定义容器的比较函数std::less 关联容器set/map等 在模板参数中指定自定义比较类型 // 方法1函数对象推荐
struct CustomCompare { bool operator()(const T a, const T b) const { return /* 自定义逻辑 */; // 例a.salary b.salary }
};
std::setT, CustomCompare mySet; // 方法2LambdaC11
auto comp [](const T a, const T b) { /* ... */ };
std::setT, decltype(comp) mySet(comp); // 需传递Lambda对象 序列容器vector/list等 在排序操作时传入比较函数 std::vectorT vec;
// 方法1Lambda表达式
std::sort(vec.begin(), vec.end(), [](const T a, const T b) { return a.id b.id; // 按ID升序
}); // 方法2函数指针
bool compareFunc(const T a, const T b) { /* ... */ }
std::sort(vec.begin(), vec.end(), compareFunc); 优先队列priority_queue 在模板参数中指定比较类型 // 小顶堆示例
struct Greater { bool operator()(int a, int b) const { return a b; // 小值优先 }
};
std::priority_queueint, std::vectorint, Greater minHeap; 关键规则 严格弱序要求 需满足 !comp(a, a) // 非自反
comp(a, b) !comp(b, a) // 非对称
comp(a, b) comp(b, c) comp(a, c) // 传递性 违反示例错误 [](int a, int b) { return a b; } // 包含相等违反非自反性 比较对象类型 函数对象需重载 operator() 且为 const 成员函数Lambda推荐捕获列表为空无状态 性能影响 关联容器比较函数复杂度需为 O(1)否则树操作退化为 O(n log n)排序操作比较函数应轻量高频调用 无序关联容器std::unordered_set, std::unordered_multiset, std::unordered_map, std::unordered_multimap 各自的特点、底层实现哈希表、优缺点和适用场景 容器特点底层实现优点缺点适用场景std::unordered_set唯一键集合无序存储哈希表桶链表/红黑树平均 O(1) 查找/插入最坏 O(n)内存占用高快速去重如URL黑名单std::unordered_multiset键可重复无序存储同上支持重复键同 unordered_set词频统计如单词计数std::unordered_map键值对键唯一无序存储同上平均 O(1) 键值访问同 unordered_set高速键值查询如缓存std::unordered_multimap键值对键可重复无序存储同上支持一键多值同 unordered_set多值映射如电话簿 底层实现核心 哈希表 桶数组连续内存 冲突解决结构链表/红黑树C11 优化桶内元素超阈值如 GCC 为 8时链表转红黑树最坏复杂度优化至 O(log n) 哈希冲突的解决方法 方法原理实现示例特点链地址法桶内挂链表存储冲突元素bucket[i] head→a→b→null简单通用C标准库默认方案开放寻址法线性探测冲突时找下一个空桶bucket[(hash1)%size]缓存友好需负载因子控制罗宾汉哈希冲突时比较探测距离抢占更远槽位复杂优化减少最长探测距离 关键参数 负载因子 元素数 / 桶数默认 1.0扩容触发负载因子 max_load_factor() 时桶数翻倍并重哈希 如何自定义容器的比较函数 需定义 两个函数对象 哈希函数计算键的哈希值键相等比较判断键是否相同 // 示例自定义Point类型作为键
struct Point { int x; int y; }; // 1. 自定义哈希函数
struct PointHash { size_t operator()(const Point p) const { return std::hashint()(p.x) ^ (std::hashint()(p.y) 1); }
}; // 2. 自定义键相等比较
struct PointEqual { bool operator()(const Point a, const Point b) const { return a.x b.x a.y b.y; }
}; // 定义容器
std::unordered_mapPoint, std::string, PointHash, PointEqual pointMap; 关键规则 哈希一致性若 a b则 hash(a) hash(b) 性能要求哈希函数需高效O(1) 复杂度 特化 std::hash可选 namespace std {
template struct hashPoint { /* ... */ };
} 容器配合std::stack, std::queue, , std::priority_queue 各自的特点、底层实现、优缺点和适用场景 适配器特点默认底层容器核心操作优点缺点适用场景std::stack后进先出LIFOstd::dequepush(), pop(), top()操作简单高效O(1)只能访问顶部元素函数调用栈/撤销操作/括号匹配std::queue先进先出FIFOstd::dequepush(), pop(), front()头尾操作高效O(1)只能访问两端元素消息队列/缓冲区/广度优先搜索std::priority_queue优先级队列最大堆std::vectorpush(), pop(), top()高效获取极值O(1)插入慢O(log n)任务调度/事件处理/Dijkstra算法 底层实现详解 stack queue 默认容器选择 使用 deque双端队列原因 两端插入/删除均为 O(1) 内存自动扩展避免 vector 扩容时的全量拷贝 示例 std::stackint s; // 等价于 std::stackint, std::dequeint
std::queuechar q; // 等价于 std::queuechar, std::dequechar priority_queue 实现原理 基于 堆结构完全二叉树 底层容器需支持 随机访问operator[]→ 故用 vector前端插入/删除push_back(), pop_back() 堆操作 // 插入元素上浮
vec.push_back(x);
std::push_heap(vec.begin(), vec.end());// 删除顶部下沉
std::pop_heap(vec.begin(), vec.end());
vec.pop_back();自定义底层容器 // 使用 vector 作为 stack 的底层容器
std::stackint, std::vectorint vecStack; // 使用 list 作为 queue 的底层容器
std::queueint, std::listint listQueue; // 使用 deque 作为 priority_queue 的底层容器
std::priority_queueint, std::dequeint dequePQ; 注意限制 stack需支持 push_back(), pop_back(), back()queue需支持 push_back(), pop_front(), front()priority_queue需支持随机访问迭代器 front() 性能与选择指南 stack/queue vs 原生容器 优先用适配器语义明确 防止误操作需要中间访问时 → 改用 deque priority_queue 优化 自定义比较器实现最小堆 std::priority_queueint, std::vectorint, std::greaterint minHeap;复杂类型场景 struct Task { int priority; /*...*/ };
auto comp [](const Task a, const Task b) { return a.priority b.priority;
};
std::priority_queueTask, std::vectorTask, decltype(comp) taskQueue(comp);内存敏感场景 固定大小栈 → 用 array 替代 deque std::stackint, std::arrayint, 100 fixedStack;2. 修改算法算法 *问题类型 常用的非式修改序列操作std::for_each, std::find,std::count等 算法功能示例std::for_each对每个元素执行操作for_each(v.begin(), v.end(), print)std::find查找首个匹配元素find(v.begin(), v.end(), 42)std::find_if查找首个满足条件的元素find_if(v.begin(), v.end(), isEven)std::count统计匹配元素数量count(v.begin(), v.end(), a)std::count_if统计满足条件的元素数量count_if(v.begin(), v.end(), isPrime)std::all_of检查所有元素满足条件 (C11)all_of(v.begin(), v.end(), isPositive)std::any_of检查至少一个元素满足条件 (C11)any_of(v.begin(), v.end(), isNegative) 常用的非式序列操作std::copy, std::remove, std::sort, std::unique,std::reverse等 算法功能注意要点std::copy复制序列到目标位置目标容器需预分配空间std::remove逻辑删除匹配元素移动元素需配合 erase 物理删除见示例↓std::remove_if逻辑删除满足条件的元素同上std::sort排序默认升序需随机访问迭代器不支持 liststd::stable_sort稳定排序保持相等元素顺序性能略低于 sortstd::unique删除连续重复元素需先排序返回新逻辑终点std::reverse反转序列元素顺序list 有成员函数 reverse()删除元素标准写法 // vector 删除偶数
auto newEnd remove_if(vec.begin(), vec.end(), isEven);
vec.erase(newEnd, vec.end()); // 物理删除 常用的数值算法std::accumulate等 算法功能示例std::accumulate累加/自定义归约操作accumulate(v.begin(), v.end(), 0)std::inner_product计算内积点积inner_product(a.begin(), a.end(), b.begin(), 0)std::partial_sum生成前缀和序列partial_sum(v.begin(), v.end(), out)std::iota填充递增序列 (C11)iota(v.begin(), v.end(), 10) // 10,11,12… 如何使用这些算法以及它们与容器成员函数的区别 场景选择原因list 排序成员 sort()算法 std::sort 需随机访问不支持链表set 查找成员 find()算法 std::find 是 O(n)成员是 O(log n)关联容器删除成员 erase()算法 std::remove 破坏树结构通用序列操作STL 算法统一接口可跨容器使用 关键原则 关联容器/链表优先用成员函数性能/正确性序列容器vector/deque优先 STL 算法通用性 std::sort底层实现通常是 Introsort 混合排序策略 快速排序主递归阶段平均 O(n log n)堆排序当递归深度 2 log n 时切换避免最坏 O(n²)插入排序小区间优化n ≤ 16 时 核心优势 最坏时间复杂度 O(n log n)优于纯快排避免递归过深堆排序兜底小数据局部性优插入排序 示例代码 std::vectorint v {5, 3, 2, 8, 1};
std::sort(v.begin(), v.end()); // 升序
std::sort(v.begin(), v.end(), std::greaterint()); // 降序 3. 迭代器Iterators *问题类型 迭代器的概念和 定义迭代器是 STL 中用于 遍历容器元素 的通用抽象接口行为类似指针支持 *、-、 等操作。作用 解耦算法与容器如 std::sort 可作用于所有支持随机访问迭代器的容器提供统一的容器访问方式 五种迭代器作用类别输入、输出、前向、个体、随机访问及其特性 类别支持操作容器示例输入迭代器只读单次遍历 (*it, , , !)istream_iterator输出迭代器只写单次遍历 (*it, )ostream_iterator前向迭代器读写 多次遍历继承输入/输出forward_list, unordered_*双向迭代器前向 反向遍历 (--)list, set, map随机访问迭代器双向 跳跃访问 (itn, it[n], )vector, deque, array 层级关系 输入 → 前向 → 双向 → 随机访问 输出 → 前向 → … begin(), end(), cbegin(), cend(), rbegin(),rend()的区别 函数返回类型方向可修改性容器示例调用begin()普通迭代器正向可读写vec.begin()end()普通迭代器正向尾后不可解引用vec.end()cbegin()const 迭代器正向只读vec.cbegin()cend()const 迭代器正向尾后不可解引用vec.cend()rbegin()反向迭代器反向可读写vec.rbegin()rend()反向迭代器反向尾后不可解引用vec.rend()crbegin()const 反向迭代器反向只读vec.crbegin() 反向迭代器注意 std::vectorint v {1,2,3};
auto rit v.rbegin(); // 指向 3
*rit 4; // v {1,2,4} 迭代器故障问题何时会发生如何避免 何时发生 容器导致失效的操作vector/string插入/删除导致扩容或元素移动deque首尾外插入/删除、扩容list/forward_list仅删除时使被删元素迭代器失效关联容器仅删除时使被删元素迭代器失效 避免方法 插入后更新迭代器 auto it vec.begin();
it vec.insert(it, 10); // 获取新迭代器 删除时用返回值更新 for (auto it lst.begin(); it ! lst.end(); ) { if (*it % 2 0) it lst.erase(it); // 更新为下一个元素 else it;
} 避免失效区间操作 // 错误删除导致后续迭代器失效
for (auto it vec.begin(); it ! vec.end(); it) { if (cond) vec.erase(it); // UB!
} 关键原则 序列容器vector/deque修改后所有迭代器可能失效链表/关联容器修改后仅被删元素迭代器失效
4. 函数对象 (Functors) / Lambda 表达式 *问题类型 函数对象的概念和作用 概念重载了 operator() 的类对象可像函数一样调用 作用 可携带状态通过成员变量可作模板参数编译期多态比函数指针更高效可内联优化 示例 struct Compare { bool operator()(int a, int b) const { return a b; // 实现自定义比较 }
};
std::sort(v.begin(), v.end(), Compare()); Lambda 表达式的语法和捕获列表Capture List 语法 [捕获列表](参数) - 返回类型 { 函数体 } 捕获列表Capture List 捕获方式效果[]不捕获外部变量[x]按值捕获变量 x副本[x]按引用捕获变量 x[]按值捕获所有外部变量不推荐[]按引用捕获所有外部变量不推荐[this]捕获当前类对象的 this 指针[x expr]C14用表达式初始化捕获移动捕获 示例 int base 100;
auto add [base](int x) { return x base; };
std::cout add(5); // 输出 105 Lambda 表达式的本质 编译器行为 将 Lambda 转换为匿名函数对象类含重载的 operator() 转换示例 // Lambda: [](int x) { return x * 2; }
// 编译器生成类似
class __Lambda_123 {
public: int operator()(int x) const { return x * 2; }
}; 什么时候使用函数对象或 Lambda 表达式 场景推荐方式原因简单逻辑如比较器Lambda代码简洁无需额外定义需要携带复杂状态函数对象可定义多个成员变量/辅助方法需要递归调用函数对象Lambda 递归需 std::function性能损失需作为模板参数如容器的比较器函数对象或无捕获 Lambda无捕获 Lambda 可转换为函数指针需复用逻辑函数对象避免重复定义 关键区别 函数对象显式定义类型适合复杂/复用逻辑Lambda隐式匿名类型适合一次性简单逻辑