乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

容器选择全景指南

定义与作用

选择正确的容器对程序性能影响深远。本文提供 C++ 标准库容器的全面对比、决策树和性能基准,帮助在实战中快速做出最优选择。

核心原理

容器选择决策树

综合对比

操作复杂度矩阵

操作vectordequelistforward_listset/mapunordered_set/map
随机访问O(1)O(1)————
前端插入—O(1)O(1)O(1)O(log n)O(1)
后端插入O(1)*O(1)O(1)—O(log n)O(1)
中间插入O(n)O(n)O(1)O(1)**O(log n)O(1)
查找O(n)O(n)O(n)O(n)O(log n)O(1)
排序O(n log n)O(n log n)O(n log n)†O(n log n)†自动有序无序

* 摊销 O(1);** 需要已知前驱位置;† 成员函数 sort()

内存特性

容器内存布局额外开销缓存友好度
vector连续3 指针(begin/end/capacity)极高
array连续0极高
deque分段中控器 + 每块指针中
list分散2 指针/节点低
forward_list分散1 指针/节点低
set/map分散(树节点)3 指针 + 颜色/节点低
unordered桶数组 + 链表桶 + 节点指针中

完整示例

示例一:飞翔科技日志存储方案选择

场景说明:大翔让白歌评估飞翔科技不同业务场景下的最佳容器选择。

#include <iostream>
#include <vector>
#include <list>
#include <unordered_map>
#include <set>
#include <chrono>
#include <algorithm>
#include <numeric>

// 模拟不同场景的容器性能
int main() {
    const int N = 20000;

    // 场景1:日志追加(适合 vector)
    // 场景:李眉每天追加运维日志
    {
        std::vector<int> logEntries;
        auto start = std::chrono::high_resolution_clock::now();
        for (int i = 0; i < N; ++i)
            logEntries.push_back(i);
        auto t = std::chrono::duration<double, std::milli>(
            std::chrono::high_resolution_clock::now() - start).count();
        std::cout << "[vector push_back] " << t << " ms\n";
    }

    // 场景2:实时消息队列(适合 deque 或 list)
    // 场景:赵鸣的内容发布系统先消费旧消息、接收新消息
    {
        std::list<int> messages;
        for (int i = 0; i < N / 2; ++i) messages.push_back(i);

        auto start = std::chrono::high_resolution_clock::now();
        for (int i = 0; i < N / 4; ++i) {
            messages.pop_front();          // 消费消息 O(1)
            messages.push_back(N + i);     // 新消息 O(1)
        }
        auto t = std::chrono::duration<double, std::milli>(
            std::chrono::high_resolution_clock::now() - start).count();
        std::cout << "[list pop_front+push_back] " << t << " ms\n";
    }

    // 场景3:用户在线状态(适合 unordered_map)
    // 场景:高英需要频繁查询用户在线状态
    {
        std::unordered_map<int, bool> onlineStatus;
        for (int i = 0; i < N; ++i)
            onlineStatus[i] = (i % 3 == 0);

        auto start = std::chrono::high_resolution_clock::now();
        int count = 0;
        for (int i = 0; i < N * 10; ++i)  // 大量查询
            if (onlineStatus.count(i % N)) ++count;
        auto t = std::chrono::duration<double, std::milli>(
            std::chrono::high_resolution_clock::now() - start).count();
        std::cout << "[unordered_map 200K查询] " << t << " ms, 命中: " << count << "\n";
    }

    // 场景4:排行榜(适合 set/map,天然有序)
    // 场景:杨英的活动排行榜需要按积分排序
    {
        std::set<int, std::greater<int>> leaderboard;
        for (int i = 0; i < N; ++i)
            leaderboard.insert(rand() % 10000);

        std::cout << "\n[set 排行榜 Top 10]\n";
        int rank = 1;
        for (auto it = leaderboard.begin(); rank <= 10 && it != leaderboard.end(); ++it, ++rank)
            std::cout << "  #" << rank << ": " << *it << " 分\n";
    }
}

预期输出(典型):

[vector push_back] 0.6 ms
[list pop_front+push_back] 0.1 ms
[unordered_map 200K查询] 12.3 ms, 命中: 71333

[set 排行榜 Top 10]
  #1: 9983 分
  #2: 9972 分
  #3: 9951 分
  ...

逐段分析:

  • 日志追加 → vector:连续内存、缓存友好、摊销 O(1)
  • 消息队列 → list:频繁双端操作、无迭代器失效
  • 在线状态 → unordered_map:O(1) 查找、无需排序
  • 排行榜 → set:天然有序、std::greater 实现降序

示例二:场景决策对照表

场景说明:白歌为团队总结各业务模块的容器选型。

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <queue>
#include <array>

// 飞翔科技各业务模块容器选型总结
struct ContainerChoice {
    std::string module;
    std::string scenario;
    std::string container;
    std::string reason;
};

int main() {
    std::vector<ContainerChoice> choices = {
        {"孔蓝-需求池", "优先级排序", "std::priority_queue",
         "按优先级取最高,底层最大堆 O(log n) push + O(1) top"},
        {"白歌-架构监控", "服务列表(固定数量)", "std::array",
         "微服务数量固定,零开销,编译期检查"},
        {"小崔-缓存层", "KV 缓存", "std::unordered_map",
         "O(1) 平均查找,无需排序"},
        {"黄俪-UI 组件树", "组件嵌套", "std::list",
         "频繁增删子组件,迭代器不失效"},
        {"李眉-服务器日志", "日志追加", "std::vector",
         "连续内存,缓存友好,批量写入"},
        {"赵鸣-内容发布", "消息队列", "std::queue",
         "FIFO 语义清晰,deque 底层双端高效"},
        {"高英-用户排行榜", "有序排名", "std::set",
         "红黑树自动排序,区间查询方便"},
    };

    std::cout << "=== 飞翔科技各模块容器选型 ===\n\n";
    for (const auto& c : choices) {
        std::cout << "【" << c.module << "】" << c.scenario << "\n";
        std::cout << "  选型: " << c.container << "\n";
        std::cout << "  理由: " << c.reason << "\n\n";
    }
}

逐段分析:此表可作为团队代码审查时的参考标准——每个场景都有明确的容器选择依据。

易错场景与面试考点

易错场景

1. 默认选 vector 就对了(大部分情况确实如此)

// 80% 的场景 vector 是最优选择
// 只有在需要:前端增删 / 频繁中间插入删除 / 按键查找 / 迭代器稳定 时才考虑其他

2. 过早优化:为「可能」的中间插入用了 list

// 如果实际运行时插入很少,vector 的缓存局部性优势可能远超 list 的 O(1) 插入

3. 有序需求用了 unordered_map

// unordered_map 元素无序,遍历顺序每次可能不同
// 需要有序遍历时必须用 map

面试考点

考点要点
默认首选vector(连续内存 + 缓存友好)
键值查找map(有序)vs unordered_map(快)
迭代器稳定list/forward_list/unordered(插入删除不失效)
内存敏感forward_list(最省)vs array(零开销)
双端操作deque(比 vector 前端快)
特定语义stack/queue/priority_queue
衡量标准主要操作是什么?数据量多大?是否需要有序?

快速决策表

你的需求选择
顺序存储 + 末尾增删std::vector
固定数量 + 栈分配std::array
双端增删std::deque
频繁任意位置插入/删除std::list
单向链表 + 节省内存std::forward_list
按键快速查找 + 无需有序std::unordered_map / unordered_set
按键查找 + 需要有序std::map / std::set
LIFO 语义std::stack
FIFO 语义std::queue
按优先级取最大std::priority_queue(默认最大堆)
异构固定大小集合std::tuple
上一页
容器适配器