某日二师兄加入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++!(狗头)