某日二师兄参加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指针指向的对象,而不需要移动元素的位置,所以不会导致迭代器失效。

面试官:listvector相比,有哪些优势?什么情况下使用list,什么情况下使用vector

二师兄:主要有2点优势:1.list在随机插入数据不会导致数据的搬移。2.list随机删除也不会导致数据搬移。所以在频繁的随机插入/删除的场景使用list,其他场景使用vector

面试官:你知道std::sort和list成员函数sort有什么区别吗?

二师兄:std::sort是STL算法的一部分。它排序的容器需要有随机访问迭代器,所以只能支持vectordequelist成员函数sort用于list排序,时间复杂度是O(N*logN)

面试官:forward_list了解吗?知道如何实现的吗?

二师兄:std::forward_list是C++11引入的新容器之一。它的底层是单向链表,引入它的主要目的是为了达到手写链表的性能。同时节省了部分内存空间。(只有一根指针)

面试官:listpop_front/pop_back的时候需要注意哪些问题?

二师兄:需要判断listsize()不能为0,如果list为空,pop_front/pop_back会导致coredump

面试官:你知道list的成员函数insertforward_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

面试官:遍历两个元素数目相同的vectorlist,哪个效率高?

二师兄:vectorlist的遍历效率都是O(N),效率应该是一样的。

面试官:好的,回去等通知吧。

让我们看以下二师兄今日的表现:

以下代码的输出是什么?

这里实际上会输出Segmentation fault,原因是因为当从listerase这个node,这个nodeprevnext指针被清空,而++it是通过当前的nodenext指针去找下一个node,解引用一个空指针,导致coredump

erase函数返回下一个有效迭代器,所以可以把if(0 == *it % 2) li.erase(it)修改为if(0 == *it % 2) it = li.erase(it)来解决这个问题。

遍历两个元素数目相同的vectorlist,哪个效率高?

这里二师兄回答的倒是没有毛病,但是没有考虑到缓存问题。实际上因为vector底层采用数组存储数据,所以它的空间局部性更好,对缓存更友好(Cache-friendly),所以遍历vector的效率要高于遍历list

最后多啰嗦一点,如果你没有特别的理由选择其他容器,使用vector是最好的选择。

二师兄今日的面试旅程结束了,感谢各位小伙伴的关注和点赞。为了保证面试质量,以后不一定能保证日更。文章中有任何技术性问题,请留言反馈,在此感谢!

关注我,带你21天“精通”C++!(狗头)

C++面试八股文:std::vector和std::list,如何选择?的更多相关文章

  1. 实战c++中的string系列--std:vector 和std:string相互转换(vector to stringstream)

    string.vector 互转 string 转 vector vector  vcBuf;string        stBuf("Hello DaMao!!!");----- ...

  2. std::vector与std::list效能对比(基于c++11)

    测试对象类型不同,数量级不同时,表现具有差异: 测试数据对象为std::function时: test: times(1000)vector push_back time 469 usvector e ...

  3. 编程杂谈——std::vector与List<T>的性能比较

    昨天在比较完C++中std::vector的两个方法的性能差异并留下记录后--编程杂谈--使用emplace_back取代push_back,今日尝试在C#中测试对应功能的性能. C#中对应std:: ...

  4. Item 21: 比起直接使用new优先使用std::make_unique和std::make_shared

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 让我们先从std::make_unique和std::make_s ...

  5. 使用std::map和std::list存放数据,消耗内存比实际数据大得多

    使用std::map和std::list存放数据,消耗内存比实际数据大得多 场景:项目中需要存储一个结构,如下程序段中TEST_DATA_STRU,结构占24B.但是使用代码中的std::list&l ...

  6. c++转载系列 std::vector模板库用法介绍

    来源:http://blog.csdn.net/phoebin/article/details/3864590 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作 ...

  7. C++ 中的std::vector介绍(转)

    vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec ...

  8. std::vector介绍

    vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec ...

  9. std::vector<Channel2*> m_allChannels;容器,以及如何根据channelid的意义

    std::vector<Channel2*> m_allChannels;容器,以及如何根据channelid的意义 这个容器保存了所有客户端连接的channel Channel2* Li ...

  10. std::vector数据复制

    std::vector<boost::shared_ptr <ITEM> > srcItemList;  // 数据源 std::vector<ITEM>  des ...

随机推荐

  1. flask-sqlalchemy入门

    Flask-SQLAlchemy 是一个为 Flask 应用增加 SQLAlchemy 支持的扩展.它致力于简化在 Flask 中 SQLAlchemy 的使用.SQLAlchemy 是目前pytho ...

  2. pandas之样本操作

    随机抽样,是统计学中常用的一种方法,它可以帮助我们从大量的数据中快速地构建出一组数据分析模型.在 Pandas 中,如果想要对数据集进行随机抽样,需要使用 sample() 函数.sample() 函 ...

  3. [Java/LeetCode]算法练习:转变日期格式(1507/simple)

    1 题目描述 题目来源: https://leetcode-cn.com/problems/reformat-date 给你一个字符串 date ,它的格式为 Day Month Year ,其中: ...

  4. 关于取消DevTools listening on ws://127.0.0.1…提示的方法

    Python代码写好之后,通过任务计划程序定期执行.py文件,但总会有命令窗口,虽然不影响程序执行,但每次需要手动叉掉比较烦.于是我网上搜索了一些方法. 网上的方法并没有直接解决我的问题,但我借助搜索 ...

  5. JUC(二)线程间通信

    目录 线程间通信 多线程编程步骤 一个加减实例 & 虚假唤醒问题 Lock接口实现 lock.newCondition设置等待条件 线程间定制化通信 线程间通信案例 设置标志位 线程间通信 多 ...

  6. 长连接Netty服务内存泄漏,看我如何一步步捉“虫”解决

    作者:京东科技 王长春 背景 事情要回顾到双11.11备战前夕,在那个风雨交加的夜晚,一个急促的咚咚报警,惊破了电闪雷鸣的黑夜,将沉浸在梦香,熟睡的我惊醒. 一看手机咚咚报警,不好!有大事发生了!电话 ...

  7. [MAUI]模仿网易云音乐黑胶唱片的交互实现

    @ 目录 创建页面布局 创建手势控件 创建影子控件 唱盘拨动交互 唱盘和唱针动画 项目地址 用过网易云音乐App的同学应该都比较熟悉它播放界面. 这是一个良好的交互设计,留声机的界面隐喻准确地向人们传 ...

  8. logstash增量同步mysql数据到es

    本篇本章地址:https://www.cnblogs.com/Thehorse/p/11601013.html 今天我们来讲一下logstash同步mysql数据到es 我认为呢,logstash是众 ...

  9. [双目视差] 立体匹配算法推理 - SGBM算法(一)

    文章目录 立体匹配算法推理 - SGBM算法(一) 一.SGBM与SGM的区别 二.代价计算 立体匹配算法推理 - SGBM算法(一) SGBM立体匹配算法,总体来讲包含以下6个步骤: Preproc ...

  10. 极速进化,光速转录,C++版本人工智能实时语音转文字(字幕/语音识别)Whisper.cpp实践

    业界良心OpenAI开源的Whisper模型是开源语音转文字领域的执牛耳者,白璧微瑕之处在于无法通过苹果M芯片优化转录效率,Whisper.cpp 则是 Whisper 模型的 C/C++ 移植版本, ...