23、常见容器性质总结?
- vector 底层数据结构为数组 ,支持随机访问
- list 底层数据结构为双向链表,支持快速增删
- deque 底层数据结构为一个中央控制器和多个缓冲区,支持首尾(中间不能)快速增删,支持随机访问。deque是一个双端队列(double-ended queue),也是在堆中保存内容的.它的保存形式如下:[堆1] --> [堆2] -->[堆3] --> …每个堆保存好几个元素,然后堆和堆之间有指针指向,看起来像是list和vector的结合品.
- stack 底层一般用list或deque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时(vector整篇迁移,而deque的扩容是实打实的连接一片连续空间过来)
- queue 底层一般用list或deque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时(stack和queue其实是适配器,而不叫容器,因为是对容器的再封装)
- priority_queue 的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现
- set 底层数据结构为红黑树,有序,不重复
- multiset 底层数据结构为红黑树,有序,可重复
- map 底层数据结构为红黑树,有序,不重复
- multimap 底层数据结构为红黑树,有序,可重复
- unordered_set 底层数据结构为hash表,无序,不重复
- unordered_multiset 底层数据结构为hash表,无序,可重复
- unordered_map 底层数据结构为hash表,无序,不重复
- unordered_multimap 底层数据结构为hash表,无序,可重复
27、STL中vector的实现
- arry是在栈或者全局数据区上,静态分配内存,配置后不可改变大小,灵活性差但效率高。
- vector在堆上,速度没arry快但灵活性好,动态配置空间,维护一块连续的空间,可以自动扩展容纳新元素。随机访问迭代器。扩容规则:以原大小的两倍配置另外一块较大的空间,在Linux+Gcc下是2倍,在win+vs下是1.5倍。频繁对vector调用push_back()对性能是有影响的,这是因为每插入一个元素,如果空间够用的话还能直接插入,若空间不够用,则需要重新配置空间,移动数据,释放原空间等操作,对程序性能会造成一定的影响
28、STL中slist的实现
使用单向链表实现,相比list耗用空间更小。由于是单向链表,考虑效率问题只提供了push_front()操作(头插),所以存进去顺序跟输出顺序相反。提供insert_after()和erase_after()
29、STL中list的实现
双向链表,支持在头部(front)和尾部(back)两个方向进行push和pop操作
30、STL中的deque的实现
相比vector的单端开口,deque是双端开口,头尾的增删O(1),由分段空间连接组成,不像vector的连续空间,没有容量的概念,支持随机访问迭代器。deque内部有一个指向map的指针,map的每个元素都指向另一端更大的缓冲区,缓冲区才是真正存数据的地方。所以deque的迭代器++和–操作复杂,主要工作在缓冲区边界跳到另一个缓冲区时。因此除了必要一般使用vector,如果要对deque排序一般可以复制deque元素到vector中,sort后再把结果复制回去。
当map的node都用完了,并且所有node指向的缓冲区都用完了,map将重新配置来 2*当前+2的数量来容纳更多node,也就是指向更多缓冲区。 中控器就是map
31、STL中stack和queue的实现(两者没有迭代器)
**stack:**容器配接器,不提供迭代器。stack底层是deque容器,移除了一端接口就行了,也开始使用双向开口的list实现。(源码上参数2用list就行了)
**queue:**底层也是 deque,也可以用list作为底层容器,容器配接器,没有遍历功能,没有迭代器。
32、STL中的heap的实现
- heap(堆)并不是STL的容器组件,堆排序是priority queue(优先队列)的底层实现机制。大根堆其实可以用vector跟一组heap算法实现。
- heap算法有push_heap(加入大根堆)和pop_heap(下溯,其实是放到vector末尾)
- sort(因为pop的时候会把最大值放到vector末尾,所以不断的调用,最后vector会变成一个递增序列)
- make_heap(),以vector为底层容器把一段数据转换为heap,也就是不断调用push_heap实现
33、STL中的priority_queue的实现–容器配接器
跟队列一样一端进一端出,但是进元素时是根据元素值排列进的。用vector作为底层容器,heap作为管理规则(堆排)。每次只能拿到优先队列中权值最大的那个
34、STL中set的实现?
- 迭代器是常量迭代器,不允许通过迭代器修改元素值(会破坏有序性和唯一性),set元素自动排升序,不允许重复。要修改元素值的话—>删除,再加入元素
- 底层是红黑树实现的,红黑树特点:二叉排序树、查询和维护复杂度是O(logn),根节点是黑,如果节点是红,子节点必黑,某节点到NULL的每条路径上,黑色节点数目相等。
- 关联式容器(set、map、multiset、multimap)使用自身提供的find()更快,因为通用标准库的find按顺序查找,复杂度是O(n),而关联式容器是树结构,自身的find()使用二分查找时间复杂度是O(logn)
- 无序关联式容器指的是用哈希表实现的unordder set \unordermap,查询速度是O(1)。
35、STL中map的实现
- 标准map底层是红黑树,另外有一种底层机制是哈希表的称为hash_map。
- 即带order的有序的都是红黑树实现的,优点是有序,不带order的哈希表实现,优点是查询效率高。unorder是哈希表实现的:unorder set, unorder map。
36、set和map的区别,multimap和multiset的区别
- set放值。map放键值对。
- multi跟非multi的差别就在于调用红黑树的插入的方式不同:普通的set(非multi)使用红色树的insert_unique()独一无二插入,mult使用insert_equal()可重复插入。
37、STL中unordered_map和map的区别和应用场景
map适用于有序场景,unordermap适用于高效查询场景
38、哈希表中解决冲突方法?
- 线性探测:根据hash函数计算找到第一个不冲突的,如果被占用就回到表头,直到找到一个空位
- 开链:每个表格维护一个list,hash函数计算结果与格子相同则存到这个list
- 再散列:发送冲突使用另一个hash函数再计算一个地址
学习资源来自师兄拓扑阿秀