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

c++中的STL

STL(Standard Template Library,标准模板库)是C++中的一个非常重要且强大的组成部分,它提供了丰富的模板类和函数,让我们可以高效、方便地处理数据结构和算法。下面我会以通俗易懂的方式,详细介绍STL的各个方面。


一、什么是STL?

 **STL(Standard Template Library)**是C++标准库的一部分,主要包含三大方面:

  1. 容器(Containers)
  2. 算法(Algorithms)
  3. 迭代器(Iterators)

这些工具结合在一起,让你可以快速实现数据存储、操作和处理,不用自己从零写数据结构或算法。


二、STL的三大核心组成部分

1. 容器(Containers)

容器就像不同形状的“容器箱”,用来存放各种类型的数据。不同的容器有不同的用途和特性。

常用的容器分类:

  • 序列容器:元素有序排列,可以根据位置访问
    • vector(动态数组)
    • list(双向链表)
    • deque(双端队列)
    • array(数组封装)
  • 关联容器:存放“键值对” 可以快速查找
    • set(集合,不重复元素)
    • map(映射,键值对)
    • multiset(相同元素可多次)
    • multimap
  • 无序容器(哈希容器):提供更快的查找
    • unordered_set
    • unordered_map

2. 算法(Algorithms)

STL提供了大量的算法,比如排序、查找、复制、遍历等:

  • sort()
  • find()
  • lower_bound()
  • copy()
  • merge()
  • reverse()
  • 等等

它们通常与迭代器一起使用,实现对容器中元素的操作。

3. 迭代器(Iterators)

迭代器就像指针,用于遍历容器中的元素。例如:

  • begin()获取容器的起点
  • end()获取终点后面一个位置(用来界定遍历范围)

迭代器的作用是抽象出不同容器的遍历方式,让算法可以统一操作各种容器。


三、STL的详细介绍

3.1 容器细节

容器类型描述典型场景访问方式
vector动态数组,存放连续元素需要频繁随机访问,增加/删除末尾索引访问 [i]
list双向链表频繁插入/删除操作,位置不定迭代器操作
deque双端队列,头尾都可以快速插入删除需要两端快速操作索引和迭代器操作
array固定大小数组(类似C数组)大小固定不变时使用索引访问
set不重复元素的集合存放唯一元素,实现集合操作迭代器遍历
multiset允许重复元素的集合存放多份相同元素
map键值对(关联数组)快速查找、存储关联数据通过键访问
multimap支持重复键的映射一个键对应多个值
unordered_setunordered_map基于哈希的容器,操作更快大数据场景,追求速度

3.2 常用容器简介

vector(动态数组)
#include <vector>
std::vector<int> v;
v.push_back(10); //在末尾添加元素
v[0]; // 索引访问
v.size(); // 获取元素个数
list(链表)
#include <list>
std::list<int> lst;
lst.push_back(20);
auto it = lst.begin();
set(集合)
#include <set>
std::set<int> s;
s.insert(5);
auto it = s.find(5);
if (it != s.end()) { /* 找到元素 */ }

3.3 容器的适用场景总结

  • 如果需要频繁随机访问元素,用vector
  • 如果需要频繁插入删除,用listdeque
  • 需要有序元素或去重,用set
  • 需要快速查找,用unordered_map

四、STL算法详解

STL中的算法是模板函数,操作容器或区间。

以下是一些基础算法:

#include <algorithm> //包含算法
std::vector<int> v = {3, 1, 4, 1, 5};
std::sort(v.begin(), v.end()); // 排序
auto it = std::find(v.begin(), v.end(), 4); // 查找
std::reverse(v.begin(), v.end()); // 反转

常用算法介绍

  • sort():排序
  • find():查找
  • binary_search():二分查找(容器已排序)
  • copy():复制区间
  • merge():合并两个已排序的区间
  • for_each():对范围内元素应用函数
  • remove():移除元素(实际不改变容器,只是在区间操作,结合erase)

示例:排序和查找

#include <algorithm>
#include <vector>
#include <iostream>int main() {std::vector<int> nums = {4, 2, 7, 1, 3};std::sort(nums.begin(), nums.end()); // 排序if (std::binary_search(nums.begin(), nums.end(), 3))std::cout << "存在3\n";
}

五、迭代器详解

迭代器像指针一样,提供统一的访问接口。

常用迭代器类别:

  • 输入迭代器(只读,前向)
  • 输出迭代器(只写)
  • 前向迭代器(多次遍历,支持++
  • 双向迭代器(前后都可以遍历)
  • 随机访问迭代器(支持索引访问,比如vector的begin()end()

示例:

#include <vector>
#include <algorithm>
#include <iostream>int main() {std::vector<int> v = {1, 2, 3};for (auto it = v.begin(); it != v.end(); ++it) {std::cout << *it << " ";}
}

六、STL的实用技巧和注意事项

  • 模板的灵活性:STL模板让算法和容器适用于各种类型。
  • 头文件:常用如<vector><algorithm><map><set>等。
  • 避免越界:尽量用at()或检查size()
  • 了解容器的复杂度:比如,vector插入末尾是O(1),中间插入是O(n)

七、总结

  • STL让C++变得更强大:提供了许多强大的工具,减少自己造轮子。
  • 设计原则:容器存数据,算法操作数据,迭代器连接二者。
  • 学习建议
    • 重点掌握vectorlistmapset的使用。
    • 熟悉常用算法的用法。
    • 结合具体场景,选择合适的容器。

八、结语

STL确实是C++的“神器”,掌握好它可以大大提高编程效率和代码质量。建议你通过多写多练,理解每个容器和算法背后的设计思想,慢慢就会觉得它们变得非常自然。

深入理解mapunordered_map等容器的底层实现,有助于你更好地选择数据结构,以及理解它们的性能特点。让我用通俗易懂的方式一一讲解,特别是它们的底层原理。


一、概览:mapunordered_map的区别

特性mapunordered_map
存储结构平衡二叉搜索树(通常为红黑树)哈希表
元素有序有序(根据键的大小排序)无序
操作复杂度(查找插入)O(log n)平均为O(1),最坏O(n)(冲突严重时)
存储空间稍大一些更节省空间(哈希冲突导致额外空间)

二、map的底层实现:平衡二叉搜索树(红黑树)

1. 什么是红黑树?

  • 红黑树是一种自平衡的二叉搜索树,保证树的高度在O(log n)范围内。
  • 树的每个节点有颜色(红或黑)。
  • 特性:红黑树的插入、删除会调整颜色和旋转,确保树保持平衡。

2. map的存储

  • 所有元素(键值对)存放在红黑树的节点上。
  • 节点按键大小排序(从小到大)。

3. 访问和操作

  • 插入:类似二分搜索树,按键值插入,然后调整颜色和旋转色彩保持平衡。
  • 查找:从根节点开始,与目标键比较,沿左或右子树深入,直到找到或到达叶子。
  • 删除:找到目标节点后调整树的平衡。

4. 性能

  • 查找、插入、删除:O(log n),因为树的高度为log n

三、unordered_map的底层实现:哈希表

1. 什么是哈希表?

  • 哈希表通过哈希函数将键映射到数组的某个位置(桶/桶数组)。
  • 支持平均O(1)的查找、插入和删除。

2. 核心原理

(a)哈希函数
  • 将键(如整数、字符串)通过算法转化为一个“哈希值”。
  • 这个哈希值经过“取模”操作,得到存放位置(索引)。
(b)桶(Bucket)
  • 数组中的每个位置叫“桶”。
  • 每个桶可以存放多个元素(解决哈希冲突的方法之一是链表法)。
(c)冲突处理
  • 链表法(链式法):每个桶维护一个链表或其他结构,多个元素可能映射到同一桶。
  • 开放地址法(较少用):当发生哈希冲突时,沿探查(线性或二次探查)找到下一个空桶。

3. 具体流程

  • 插入:计算哈希值→取模→存放到对应桶的链表中(或开放地址法找到位置)。
  • 查找:计算哈希值→找到对应桶→在链表中逐个比较键,找到目标。

4. 性能

  • 平均复杂度
    • 查找、插入、删除:O(1)(理想情况下)
  • 最坏复杂度
    • 当哈希函数碰撞严重,所有元素都在同一个桶,变成链表或链表变长,效率退化到O(n)

5. 负载因子(load factor)

  • 衡量哈希表的密集程度。
  • 负载因子 = 元素数 / 桶数,若太大,会触发扩容(增加桶数,用再哈希重新存放所有元素)。

四、mapunordered_map的底层区别总结

特性mapunordered_map
底层结构红黑树哈希表
有序性有序(按键排序)无序(存储顺序不定)
操作时间复杂度O(log n)平均O(1),最坏O(n)
适用场景需要排序、范围查询追求速度、对顺序无要求
内存占用比较大(树结构)较小(哈希冲突带来的空间)
关键字类型支持支持复杂类型(需要定义比较函数)支持自定义哈希函数(定义方法)

五、通俗比喻总结

  • map:就像字典,每个词(键)对应一个定义(值),字典按字母顺序排好,查找快,插入删除相对耗时(因为要保持排序),树结构就像一棵平衡树。
  • unordered_map:像一个乱序的抽屉,把标签(键)投到不同的抽屉(桶),几乎可以即时找到物品,如果碰巧碰到同一个抽屉里的东西(哈希冲突),就像一堆杂物堆在一起,需要逐个翻找。

六、底层实现的简单示意(伪代码)

1. map(红黑树)简要模拟

复制代码

插入(key, value):如果树空->创建根节点否则:在树中搜索插入位置(类似二分搜索)插入后,调整颜色和旋转以保持平衡(红黑性质)

2. unordered_map(哈希表)简要模拟

复制代码

插入(key, value):hash_value = hash_function(key)index = hash_value % 桶数在桶(链表或其他)中查找是否存在key存在:更新值不存在:插入新元素到链表头或尾
扩容机制:当元素数超过负载因子*桶数,扩大桶数组,重新哈希所有元素

七、总结

  • map:保证有序,底层为平衡二叉树(红黑树),操作为O(log n)
  • unordered_map:无序存储,底层为哈希表,操作平均O(1)(极端情况下变为O(n)
  • 设计选择:看是否需要排序、对性能的要求,以及存储空间。
http://www.xdnf.cn/news/15219.html

相关文章:

  • Redis 实现分布式锁
  • Kotlin文件操作
  • 2025 年 4-6 月大模型备案情况分析
  • 单链表的题目,咕咕咕
  • 【Scratch】从入门到放弃(四):指令大全-九大类之事件、控制、侦测
  • 【小情绪小感悟】
  • houdini 用 vellum 制作一个最简单的布料
  • SiC 型储能充电器设计与研究
  • 岛屿数量问题
  • HT8313功放入门
  • Cell2location maps fine-grained cell types in spatial transcriptomics 文章解析
  • Golang操作MySQL json字段优雅写法
  • 【数据结构初阶】--顺序表(三)
  • 【机器学习实战笔记 16】集成学习:LightGBM算法
  • 【读书笔记】从AI到Transformer:LLM技术演进全解析
  • 智能Agent场景实战指南 Day 11:财务分析Agent系统开发
  • 动态规划基本操作
  • Vue3 学习教程,从入门到精通,Vue3指令知识点及使用方法详细介绍(6)
  • 【TOOL】ubuntu升级cmake版本
  • Linux驱动08 --- 数据库
  • 【PTA数据结构 | C语言版】后缀表达式求值
  • Mamba架构的模型 (内容由deepseek辅助汇总)
  • Edge浏览器:报告不安全的站点的解决方案
  • JAVA线程池详解+学习笔记
  • 鸿蒙NDK开发技巧之-----HAP包如何引入HSP包后,如何给HSP的包传递上下文
  • 非欧几里得空间图卷积算子设计:突破几何限制的图神经网络新范式
  • 从LLM到VLM:视觉语言模型的核心技术与Python实现
  • 如何搭建一个高质量的开放接口平台
  • 顺序队列和链式队列
  • HTML(上)