登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
每日签到
每天签到奖励2圆-6圆
发帖说明
VIP申请
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
写记录
写博客
VIP申请
VIP网盘
网盘
联系我们
每日签到
道具
勋章
任务
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
安全
›
打破迷思:为什么资深C++开发者几乎总是选择vector而非l ...
打破迷思:为什么资深C++开发者几乎总是选择vector而非list
[ 复制链接 ]
后沛若
2025-6-1 21:07:14
大家好,我是小康。
前言:打破你对容器选择的固有认知
嘿,C++小伙伴们!面对这段代码,你会怎么选?
// 存储用户信息,需要频繁查找、偶尔在中间插入删除
// 选择哪个容器实现?
std::vector<UserInfo> users; // 还是
std::list<UserInfo> users; // ?
复制代码
如果你刚学习C++,可能会想:"数据会变动,肯定用list啊!教材上说链表插入删除快嘛!"
然后有一天,你看到一位经验丰富的同事把所有list都改成了vector,并且代码性能提升了,你一脸懵逼: "这跟我学的不一样啊!"
是的,传统教科书告诉我们
:
数组(vector):随机访问快,插入删除慢
链表(list):插入删除快,随机访问慢
但实际工作中,大多数资深C++开发者却几乎总是使用vector。为什么会这样?是教材错了,还是大佬们有什么不可告人的秘密?
今天,我要带你进入真实的C++江湖,揭开vector和list性能的真相,帮你彻底搞懂这个看似简单却被无数程序员误解的选择题。
深入阅读后,你会发现:这个选择背后,涉及现代计算机体系结构、内存模型和真实世界的性能考量,而不仅仅是算法复杂度的简单对比。
微信搜索 【
跟着小康学编程
】,关注我,定期分享计算机编程硬核技术文章。
一、理论上:vector和list各是什么?
先来个直观的比喻
:
vector就像一排连续的座位
:大家坐在一起,找人超快,但中间插入一个人就需要后面的人都往后挪。
list就像一群手拉手的人
:每个人只知道自己左右邻居是谁,找到第n个人必须从头数,但中间插入一个人只需要改变两边人的"指向"。
技术上讲
:
vector
:连续内存,支持随机访问(可以直接访问任意位置),内存布局紧凑
list
:双向链表,只支持顺序访问(必须从头/尾遍历),内存布局分散
vector和list的内部结构对比
vector的内部结构
:
[元素0][元素1][元素2][元素3][元素4][...]
↑ ↑
begin() end()
复制代码
vector内部其实就是一个动态扩展的数组,它有三个重要指针:
指向数组开始位置的指针start
指向最后一个元素后面位置的指针end
指向已分配内存末尾的指针(容量capacity)
当空间不够时,vector会重新分配一块更大的内存(通常是当前大小的1.5或2倍),然后把所有元素搬过去,就像搬家一样。
list的内部结构
:
┌──────┐ ┌──────┐ ┌──────┐
│ prev │◄───┤ prev │◄───┤ prev │
┌──┤ data │ │ data │ │ data │
│ │ next │───►│ next │───►│ next │
│ └──────┘ └──────┘ └──────┘
│ 节点0 节点1 节点2
↓
nullptr
复制代码
list是由一个个独立的节点组成,每个节点包含三部分:
存储的数据
指向前一个节点的指针
指向后一个节点的指针
这就像一个手拉手的圆圈游戏,每个人只能看到左右两个人,要找到第五个人,必须从第一个开始数。
这两种容器结构上的差异,决定了它们在不同操作上的性能表现。vector因为内存连续,所以可以通过简单的指针算术直接跳到任意位置;而list必须一个节点一个节点地遍历才能到达指定位置。
按照传统教科书,它们的复杂度对比是这样的
:
操作vectorlist随机访问O(1)O(n)头部插入/删除O(n)O(1)尾部插入/删除均摊 O(1)O(1)中间插入/删除O(n)O(1)**
注意
:list 的中间插入/删除是O(1),但前提是你已经有了指向该位置的迭代器,找到这个位置通常需要O(n)时间。
看上去 list 在插入删除方面优势明显,但为什么那么多经验丰富的程序员却建议"几乎总是用vector"呢?
二、现实很残酷:理论≠实践
老铁,上面的理论分析忽略了一个超级重要的现代计算机特性:
缓存友好性
。
什么是缓存友好性?
想象你去图书馆看书:
vector就像是把一整本书借出来放在你桌上(数据连续存储)
list就像是每看一页就得去书架上找下一页(数据分散存储)
现代CPU都有缓存机制,当访问一块内存时,会把周围的数据也一并加载到缓存。对于连续存储的vector,这意味着一次加载多个元素;而对于分散存储的list,每次可能只能有效加载一个节点。
实际性能测试
我做了一个简单测试,分别用vector和list存储100万个整数,然后遍历求和:
// Vector遍历测试 - 使用微秒计时更精确
auto start = chrono::high_resolution_clock::now();
int sum_vec = 0;
for (auto& num : vec) {
sum_vec += num;
}
auto end = chrono::high_resolution_clock::now();
auto vector_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
// List遍历测试 - 使用微秒计时更精确
start = chrono::high_resolution_clock::now();
int sum_list = 0;
for (auto& num : lst) {
sum_list += num;
}
end = chrono::high_resolution_clock::now();
auto list_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
// 输出结果 - 微秒显示,并转换为毫秒显示
....
复制代码
结果震惊了我
:
这是30几倍的差距!为啥?就是因为缓存友好性!
三、list的"快速插入"真的快吗?
我们再来测试一下在容器中间位置插入元素的性能:
[code] cout
打破
迷思
为什么
资深
开发者
相关帖子
记录---前端实现倒计时为什么会存在误差呢
为什么说jobleap.cn是最适合大学生找工作的App
GraphRAG为什么能提升检索准确率
Why框架元推理,为什么是认知奇点?AI新范式
园子的不务正业:向创业开发者推荐一个「楼盘」
属于 PHP 开发者的 Supervisor 实用指南
【URP】法线贴图为什么主要是蓝色的?
打破场景边界,支付宝联合实况窗提供全新出行服务体验
3天赚2万!开发者的梦想也可以掷地有声!
领导骂我,我为什么不在意
vip免费申请,1年只需15美金$
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
安全
记录---前端实现倒计时为什么会存在误差呢
0
247
扈梅风
2025-08-30
安全
为什么说jobleap.cn是最适合大学生找工作的App
0
678
闾丘婉奕
2025-08-31
安全
GraphRAG为什么能提升检索准确率
0
738
缑莺韵
2025-08-31
业界
Why框架元推理,为什么是认知奇点?AI新范式
0
38
慎气
2025-09-03
业界
园子的不务正业:向创业开发者推荐一个「楼盘」
0
371
镝赋洧
2025-09-04
业界
属于 PHP 开发者的 Supervisor 实用指南
0
488
缣移双
2025-09-07
业界
【URP】法线贴图为什么主要是蓝色的?
0
1007
僻嘶
2025-09-07
业界
打破场景边界,支付宝联合实况窗提供全新出行服务体验
0
59
能氐吨
2025-09-09
业界
3天赚2万!开发者的梦想也可以掷地有声!
0
375
即息极
2025-09-10
业界
领导骂我,我为什么不在意
0
417
老僻贞
2025-09-10
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
浏览过的版块
业界
签约作者
程序园优秀签约作者
发帖
后沛若
2025-6-1 21:07:14
关注
0
粉丝关注
21
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
敖可
9984
杭环
9988
凶契帽
9988
4
氛疵
9988
5
黎瑞芝
9988
6
猷咎
9986
7
里豳朝
9986
8
肿圬后
9986
9
蝓俟佐
9984
10
虽裘侪
9984
查看更多