C++面试八股文:std::vector和std::list,如何选择?
某日二师兄参加XXX科技公司的C++工程师开发岗位第24面:
面试官:
list用过吗?二师兄:嗯,用过。
面试官:请讲一下
list的实现原理。二师兄:
std::list被称为双向链表,和C中手写双向链表本质上没有大的区别。list对象中有两个指针,一个指向上一个节点(node),一个指向下一个节点(node)。二师兄:与手写双向链表不同的是,
list中有一个base node,此node并不存储数据,从C++11开始,此node中包含一个size_t类型的成员变量,用来记录list的长度。二师兄:所以说从C++11开始,
size()的时间复杂度是O(1),在此之前是O(N)。面试官:是每个
node都包含一个记录长度的成员变量吗?二师兄:不是,GCC中的实现只有在
header node上记录了长度信息,其他node并没有记录。
struct _List_node_base
{
_List_node_base* _M_next;
_List_node_base* _M_prev;
...
};
struct _List_node_header : public _List_node_base
{
#if _GLIBCXX_USE_CXX11_ABI
std::size_t _M_size;
#endif
...
};

面试官:添加和删除元素会导致迭代器失效吗?
二师兄:并不会,因为在任意位置添加和删除元素只需要改变
prev/next指针指向的对象,而不需要移动元素的位置,所以不会导致迭代器失效。面试官:
list和vector相比,有哪些优势?什么情况下使用list,什么情况下使用vector?二师兄:主要有2点优势:1.
list在随机插入数据不会导致数据的搬移。2.list随机删除也不会导致数据搬移。所以在频繁的随机插入/删除的场景使用list,其他场景使用vector。面试官:你知道
std::sort和list成员函数sort有什么区别吗?二师兄:
std::sort是STL算法的一部分。它排序的容器需要有随机访问迭代器,所以只能支持vector和deque。list成员函数sort用于list排序,时间复杂度是O(N*logN)。面试官:
forward_list了解吗?知道如何实现的吗?二师兄:
std::forward_list是C++11引入的新容器之一。它的底层是单向链表,引入它的主要目的是为了达到手写链表的性能。同时节省了部分内存空间。(只有一根指针)

面试官:
list在pop_front/pop_back的时候需要注意哪些问题?二师兄:需要判断
list的size()不能为0,如果list为空,pop_front/pop_back会导致coredump。面试官:你知道
list的成员函数insert和forward_list的成员函数的insert_after有什么区别?二师兄:两者都可以向特定位置添加元素。不同的是
insert把元素插入到当前迭代器前,而insert_after把元素插入到当前迭代器后。面试官:以下代码的输出是什么?
#include <iostream>
#include <list>
int main(int argc, char const *argv[])
{
std::list<int> li = {1,2,3,4,5,6};
for(auto it = li.begin(); it!= li.end(); ++it)
{
if(0 == *it % 2) li.erase(it);
}
for(auto& i : li) std::cout << i << " ";
std::cout << std::endl;
}
二师兄:应该是
1 3 5。面试官:遍历两个元素数目相同的
vector和list,哪个效率高?二师兄:
vector和list的遍历效率都是O(N),效率应该是一样的。面试官:好的,回去等通知吧。
让我们看以下二师兄今日的表现:
以下代码的输出是什么?
这里实际上会输出Segmentation fault,原因是因为当从list中erase这个node,这个node的prev和next指针被清空,而++it是通过当前的node的next指针去找下一个node,解引用一个空指针,导致coredump。
erase函数返回下一个有效迭代器,所以可以把if(0 == *it % 2) li.erase(it)修改为if(0 == *it % 2) it = li.erase(it)来解决这个问题。
遍历两个元素数目相同的
vector和list,哪个效率高?
这里二师兄回答的倒是没有毛病,但是没有考虑到缓存问题。实际上因为vector底层采用数组存储数据,所以它的空间局部性更好,对缓存更友好(Cache-friendly),所以遍历vector的效率要高于遍历list。
最后多啰嗦一点,如果你没有特别的理由选择其他容器,使用vector是最好的选择。
二师兄今日的面试旅程结束了,感谢各位小伙伴的关注和点赞。为了保证面试质量,以后不一定能保证日更。文章中有任何技术性问题,请留言反馈,在此感谢!
关注我,带你21天“精通”C++!(狗头)
C++面试八股文:std::vector和std::list,如何选择?的更多相关文章
- 实战c++中的string系列--std:vector 和std:string相互转换(vector to stringstream)
string.vector 互转 string 转 vector vector vcBuf;string stBuf("Hello DaMao!!!");----- ...
- std::vector与std::list效能对比(基于c++11)
测试对象类型不同,数量级不同时,表现具有差异: 测试数据对象为std::function时: test: times(1000)vector push_back time 469 usvector e ...
- 编程杂谈——std::vector与List<T>的性能比较
昨天在比较完C++中std::vector的两个方法的性能差异并留下记录后--编程杂谈--使用emplace_back取代push_back,今日尝试在C#中测试对应功能的性能. C#中对应std:: ...
- Item 21: 比起直接使用new优先使用std::make_unique和std::make_shared
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 让我们先从std::make_unique和std::make_s ...
- 使用std::map和std::list存放数据,消耗内存比实际数据大得多
使用std::map和std::list存放数据,消耗内存比实际数据大得多 场景:项目中需要存储一个结构,如下程序段中TEST_DATA_STRU,结构占24B.但是使用代码中的std::list&l ...
- c++转载系列 std::vector模板库用法介绍
来源:http://blog.csdn.net/phoebin/article/details/3864590 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作 ...
- C++ 中的std::vector介绍(转)
vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec ...
- std::vector介绍
vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec ...
- std::vector<Channel2*> m_allChannels;容器,以及如何根据channelid的意义
std::vector<Channel2*> m_allChannels;容器,以及如何根据channelid的意义 这个容器保存了所有客户端连接的channel Channel2* Li ...
- std::vector数据复制
std::vector<boost::shared_ptr <ITEM> > srcItemList; // 数据源 std::vector<ITEM> des ...
随机推荐
- python实现员工信息表
学习python时,看到的一个题目第一次写博客, 有误的地方还请大佬们指正,十分感谢~要求如下'''文件存储格式如下:id,name,age,phone,job(这行不需要写)1,alice,22,1 ...
- LeeCode 316周赛复盘
T1:判断两个事件是否存在冲突 思路:判断两个区间是否有交集 public boolean haveConflict(String[] event1, String[] event2) { // 比较 ...
- PHP读取XML文件的三种方式
一 用 simplexml_load_file 读取xml文件 <?php $xml_array=simplexml_load_file('person.xml'); //将XML中的数据, ...
- JQuery点击复制文本框内容的方法插件
[导读] 文章介绍了两种常用的点击复制文本框内容方法,一种是but IE only,同样的这个也是我们经常使用的.优点是体积小,仅有十来行代码,但缺点也很明显,只支持IE及以IE为内核的浏览器,另一种 ...
- The first week match's mistake
比赛中的补题中的一些错误 P8506 标题计数(https://www.luogu.com.cn/problem/P8506) 第一眼下去,嗯..贪了,只读到一个'#'后边跟一个空格就+1,结果wa几 ...
- Java中的自动装箱与自动拆箱
前言 在Java中,基本数据类型与其对应的封装类之间可以进行自动转换,这种特性称为自动装箱(autoboxing)和自动拆箱(unboxing).自动装箱和自动拆箱使得我们在使用基本数据类型时更加方便 ...
- Locust 界面简介(非使用级)
一.认识Locust 1.简介 Locust是一款易于使用的分布式负载测试工具,完全基于事件,即一个locust节点也可以在一个进程中支持数千并发用户,不使用回调,通过gevent使用轻量级过程(即在 ...
- .net 6 使用 NEST 查询,时间字段传值踩坑
0x01业务描述 说明: 同事搭建的业务系统,最开始使用 log4net 记录到本地日志. 然后多个项目为了日志统一,全部记录在 Elasticsearch ,使用 log4net.Elastic ...
- Gusfield算法学习
算法详解 等价流树正如其名,树上两点间的路径上的边权最小值为图上两点间的最小割. Gusfield算法就是建等价流树的一种算法.设当前正在处理的集合为 \(S(|S|\ge 2)\),从 \(S\) ...
- 2021-01-23:LFU手撸,说下时间复杂度和空间复杂度。
福哥答案2021-01-23:这道题复杂度太高,短时间内很难写出来.面试的时候不建议手撕代码.一个存节点的map+一个存桶的map+一个存桶的双向链表.桶本身也是一个双向链表.存节点的map:key是 ...