STL介绍?
主要包括三类:算法、容器和迭代器
- 算法:容器中数据的处理,包括排序,复制等
- 容器分为:序列式容器(vector、list) 关联式容器(set 、map)
- 迭代器:就是在不暴露容器内部结构的情况下对容器的遍历
各容器的优缺点?
vector
数组
高效随机访问
动态查找超过自身容量的需要申请大两倍的拷贝过程
当插入(push_back)一个元素后,end 操作返回的迭代器肯定失效。若 capacity 返回值没有改变,则 first 返回的迭代器依旧有效;否则,first迭代器也失效
list
链表
任意位置插入、删除元素是常量时间复杂度
删除操作也只有指向被删除元素的那个迭代器失效,其他迭代器不受影响
deque
数据模式是数组和链表的这种(是stack和queue的基础),双向链表
在容器首部尾部插入元素不会使得任何迭代器失效,但是其他位置的插入和删除操作会使得所有的迭代器失效
在首部或尾部删除元素,只会使得被删除的元素的迭代器失效
Map
mmuitimap
set
multiset
vector的resize和reserve的区别?
- resize:改变容器大小,并创建对象,即resize是带初始化的
- reserve:容器预留空间,并不真正创建元素对象。
STL中vector的实现?
vector可以根据需要自动扩大容器的大小。不够用时,会重新申请大原来容量两倍的内存,将原容器拷贝到新容器,并释放原空间,返回新空间的指针
因此对于频繁插入,最好先指定vector的大小。因为容量不够时,每次调用push_back都会重新分配新的空间
vector中的push_back与emplace_back的区别?
pushu_back:首先会调用构造函数创建这个临时对象,然后调用拷贝构造函数将这个临时对象放入容器中,最后是释放原来的临时对象。
引入了右值引用,转移构造函数后,push_back()右值时就会调用构造函数和转移构造函数,如果可以在插入的时候直接构造,就只需要构造一次即可
emplace_back:在容器尾部添加一个元素,这个元素原地构造,不需要触发拷贝构造和转移构造。
STL中的排序算法sort的实现?
数据量较大时,采用快速排序,分段递归
数据量小于某个阈值(16)时,改用插入排序
为避免递归调用带来的负荷,递归达到一定程度采用堆排序
递归会导致栈溢出:因为每次调用递归函数都会在栈中分配空间,每个进程的栈空间容量都是有限的。
堆排序与快速排序的区别?
堆排序数据访问方式没有快速排序友好。快速排序是顺序访问的,堆排序数据是跳着访问的。
同样的数据,堆排序算法数据交换次数要多于快速排序
STL源码中的hash表的实现?
STL中的hash表就是unordered_map。使用的是哈希进行实现。记录的键是元素的哈希值。
unordered_map的底层实现是hashtable,采用开链法(也就是桶)来解决哈希冲突,当桶的大小超过8时,就自动转为红黑树进行组织。
关联容器的插入效率一般比其他序列容器高?
关联容器(list,set map)不需要做内存拷贝和内存移动。变换的时候,只需要堆指针进行操作即可
unordered_map 和 map 的实现机制性能差异?
map的内部实现是二叉平衡树(红黑树),有序的
unordered_map:哈希表,无序的
map和set的区别?
- 都属于关联性容器,底层数据结构都是红黑树
- 时间复杂度均是红黑树的时间复杂度,O(logN)
- set中所有元素都会被自动排序
- map中所有元素是通过键进行自动排序的
- map适合存储一个数据字典,并要求方便根据key找value。set适合查找一个元素是否在某个集合内存中
set不能直接改变元素的值。需要先删除旧元素,在插入新元素
map的key是不能修改的,但是可以通过key改变value的值
插入复杂度比较?
- set、map的插入复杂度就是红黑树的插入复杂度,log(N)
- unordered_set,unordered_map的插入复杂度是O(1),最坏是O(N)
- vector的插入复杂度是O(N)(最坏的情况是从头插入)
没有遍历行为的容器?(不提供迭代器)
queue:除了头部外,没有其他方法存取deque的其他元素
stack:除了最顶端外,没有任何其他方法可以存取stack的其他元素