C++ 基础数据结构与 STL 容器详解

C++ 基础数据结构与 STL 容器详解

C++ 的基础数据结构和 STL 容器是编程的核心基础,不同容器因底层实现不同,适用场景也天差地别。下面我会按「基础数据结构(语言内置)」和「STL 容器(标准库)」两类,清晰讲解它们的底层实现和核心特点,内容兼顾新手易懂性和实用性。

一、C++ 基础数据结构(语言内置)

这类是 C++ 原生支持的基础类型/结构,无复杂封装,是 STL 容器的底层基石。

数据结构 底层实现原理 核心特点
数组(array) 连续的内存空间,元素按索引顺序存储,编译期确定大小(栈/静态区分配)。 随机访问 O(1),增删 O(n),大小不可变
指针 本质是存储内存地址的变量,通过地址间接访问数据。 灵活操作内存,需手动管理,易出越界/野指针问题
结构体(struct) 把不同类型数据打包在连续内存中(内存对齐),无额外封装。 自定义复合类型,仅数据聚合,无成员函数(可手动加)
示例:原生数组的底层体现
C++ 复制代码
#include <iostream>
using namespace std;

int main() {
    // 连续内存存储:地址依次递增(int 占4字节,地址差4)
    int arr[3] = {10, 20, 30};
    cout << "arr[0] 地址:" << &arr[0] << endl;
    cout << "arr[1] 地址:" << &arr[1] << endl;
    cout << "arr[2] 地址:" << &arr[2] << endl;
    
    // 随机访问:通过 基地址 + 索引*类型大小 直接定位(O(1))
    cout << arr[1] << endl; // 等价于 *(arr + 1)
    return 0;
}

二、C++ STL 容器(标准库封装)

STL 容器是对基础数据结构的封装,分为「序列式容器」「关联式容器」「适配器容器」三类,底层实现各有侧重:

1. 序列式容器(按插入顺序存储,元素有序)
容器 底层实现原理 核心特点 适用场景
vector 动态数组,连续内存 + 预分配「容量(capacity)」,满了后扩容(通常2倍),重新分配内存并拷贝元素。 随机访问 O(1),尾部增删 O(1),中间增删 O(n) 频繁读、尾部增删,如数据遍历/统计
list 双向循环链表,每个节点包含数据、前驱指针、后继指针,非连续内存。 随机访问 O(n),任意位置增删 O(1),无内存浪费 频繁插入/删除,如链表操作、任务队列
forward_list 单向链表,仅含后继指针,比 list 更节省内存。 仅单向遍历,任意位置增删 O(1),无 size() 方法 内存受限的单向遍历场景
deque 分段连续内存(数组 + 缓冲区),底层用「中控数组」管理多个连续缓冲区,首尾各有一个指针。 随机访问 O(1),首尾增删 O(1),中间增删 O(n) 双端队列、滑动窗口,如队列/栈底层
array 封装的静态数组,连续内存,编译期确定大小(栈分配),比原生数组更安全(有边界检查)。 同原生数组,不可扩容,支持 STL 算法 替代原生数组,需固定大小场景
2. 关联式容器(按键排序,元素无序)

底层依赖「红黑树」或「哈希表」,核心是快速查找:

容器 底层实现原理 核心特点 适用场景
set/multiset 红黑树(自平衡二叉搜索树),set 键唯一,multiset 键可重复,元素自动排序。 查找/插入/删除 O(logn),有序,无随机访问 有序去重、范围查找,如字典、排序集合
map/multimap 红黑树,map 键值对(键唯一),multimap 键可重复,按键排序。 set,通过键访问值 键值映射,如配置表、缓存
unordered_set/unordered_multiset 哈希表(开链法解决哈希冲突),无自动排序,键唯一/可重复。 平均查找/插入/删除 O(1),无序,最坏 O(n) 高频查找、无需排序,如去重、存在性判断
unordered_map/unordered_multimap 哈希表,键值对,无自动排序,键唯一/可重复。 unordered_set,通过键快速查值 高频键值查找,如缓存、字典
3. 适配器容器(封装其他容器,改变接口)

无独立底层,依赖上述容器适配:

容器 底层依赖(默认) 核心特点 适用场景
stack deque 后进先出(LIFO),仅支持首尾操作 栈操作,如表达式求值、回溯
queue deque 先进先出(FIFO),仅支持首尾操作 队列操作,如任务排队、消息队列
priority_queue vector + 堆(默认大顶堆) 优先级最高的元素先出,底层堆排序 优先队列,如任务调度、贪心算法

关键补充:核心底层原理拆解

1. 红黑树(set/map 底层)

红黑树是「自平衡二叉搜索树」,通过 5 条规则保证平衡(节点红/黑、根黑、叶节点黑、红节点子节点黑、任意节点到叶节点的黑节点数相同),避免二叉搜索树退化成链表,保证操作复杂度稳定在 O(logn)。

2. 哈希表(unordered_* 底层)

哈希表通过「哈希函数」将键映射到数组下标,实现 O(1) 访问;若哈希冲突(不同键映射到同一下标),STL 用「开链法」:每个下标对应一个链表,冲突元素存入链表,最坏情况下链表过长会导致操作复杂度 O(n)(可通过扩容缓解)。

3. vector 扩容机制

vector 初始容量通常为 0/1,满了后扩容为原容量的 1.5~2 倍(不同编译器不同),步骤:

  1. 分配新的更大内存;

  2. 拷贝原元素到新内存;

  3. 释放原内存;

  4. 指向新内存。

⚠️ 扩容会导致迭代器失效,建议提前用 reserve() 预分配容量。

总结

  1. 连续内存容器array/vector/deque):随机访问快,增删慢,适合读多写少场景;

  2. 链表容器list/forward_list):增删快,访问慢,适合写多读少场景;

  3. 有序关联容器set/map):红黑树实现,有序+稳定 O(logn) 操作;无序关联容器(unordered_*):哈希表实现,无序+平均 O(1) 操作,是高频查找首选;

  4. 适配器容器stack/queue):无独立底层,仅封装接口,按需选择底层容器即可。

核心选择原则:优先根据「访问/增删频率」和「是否有序」选择容器,比如高频查找选 unordered_map,有序查找选 map,尾部增删选 vector

(注:文档部分内容可能由 AI 生成)

相关推荐
郝学胜_神的一滴1 分钟前
C++11 工程级应用 06:自己造一个类似Python的Range迭代器
c++·后端
呆呆敲代码的小Y2 分钟前
【游戏开发】C# 中的迭代器
java·开发语言·c#·迭代器
benchmark_cc4 分钟前
K 线数据断层会对回测造成什么影响?从一个缺失交易日看懂量化策略为什么会失真
大数据·开发语言·数据分析·量化·股票数据·quantdash·量化数据源
benchmark_cc10 分钟前
数据 API 稳定性为什么会影响量化策略?从数据获取到信号执行的完整分析
开发语言·python·数据分析·量化·股票数据·quantdash·量化数据源
一只QAQ10 分钟前
c++项目
java·c++·算法
2601_9621803324 分钟前
python——Django 框架
开发语言·python·django
长江后浪博客24 分钟前
Conda环境下测试Intel NPU:Python版本如何选择?
开发语言·python·conda·openvino·intel npu
Chester_199937 分钟前
CSP202206C.角色授权
开发语言·数据结构·c++·蓝桥杯
艾莉丝努力练剑39 分钟前
【AI大模型接入SDK】WebSocket & SSE 协议
网络·c++·websocket·网络协议·学习·面试
码匠许师傅40 分钟前
【设计模式精讲】6.抽象工厂(Abstract Factory)
c++·设计模式