C++的STL介绍
C++ STL从广义来讲包括了三类:算法,容器和迭代器。
算法包括排序,复制等常用算法,以及不同容器特定的算法。
容器包括序列式容器和关联式容器,及list,vector等, set,map等。
迭代器就是在不暴露容器内部结构的情况下对容器的遍历。
容器优缺点
Vector 的就是数组:
优点:内存和 C 完全兼容、高效随机访问、节省空间
缺点:插入删除元素代价巨大、超过自身容量需要申请大量内存做大量(2倍)拷贝。
List 的数据结构模型是链表
优点:任意位置插入删除元素常量时间复杂度、两个容器融合是常量时间复杂度
缺点:不支持随机访问、比 vector 占用更多的存储空间
Deque 的数据模型是数组和链表的折中(stack和queue的基础)
优点:高效随机访问、内部插入删除元素效率方便、两端 push pop
缺点:内存占用比较高
Map、set、multimap、multiset 的数据结构模型是二叉树(红黑树)
优点:元素按键值排序、查找是对数时间复杂度、通过键值查找、map 提供下标访问
vector 的 resize 和 reserve 操作的区别
resize改变容器大小并初始化,可以使用[ ],并且影响.size( )。
Reserve预留容器大小,不初始化,不可以使用[ ],要使用push_back( )。
STL中vector的实现
vector可以根据需要自动扩大容器的大小。
容量不够重新申请两倍的内存,拷贝至新容器,释放原空间,返回新空间的指针。
vector使用的注意点及其原因,
频繁对 vector调用push_back()会对性产生影响。
如果需要频繁插入,最好先指定vector的大小,频繁调用 push_back()会使得程序花费很多时间在vector扩容上,会变得很慢。这种情况可以考虑使用list。
C++中vector的push_back和 emplace_back的区别
push_back()
首先调用构造函数构造这个临时对象,然后调用拷贝构造函数将这个临时对象放入容器中。原来的临时变量释放。这样造成的问题就是临时变量 申请资源的浪费
emplace_back()
在容器尾部添加一个元素,这个元素原地构造,不需要触发拷贝构造和转移 构造。而且调用形式更加简洁,直接根据参数初始化临时对象的成员。
STL 中排序算法 sort 的实现是什么同 ?
STL的sort算法,数据量较大的时候,采用快速排序,分段递归。一旦分 段后数据量小于某个阀值(16),改用插入排序。为避免递归调用带来的 额外负荷,递归到达一定层次采用堆排序。深度递归压栈会造成栈溢出。
STL的容器线程不安全怎么解决
1.加锁是一种解决方案,但是加std::mutex互斥锁确实性能较差。对于多读 少写的场景可以用读写锁(也叫共享独占锁),来缓解。
2.更多的时候,其实可以通过固定vector的大小,避免动态扩容(无 push_back)来做到lock-free!
哪些容器都使用sort算法? vector、deque,适用sort算法。
为什么对于区间小于16的采用插入排序, 如果递归深度恶化改用堆排序?
插入排序对于基本有序或数据较少的序列很高效。
堆排序的时间复杂度固定为O(nlogn),不需要再递归下去了
堆排序是O(nlogn)直接用堆排序实现sort不行吗?为啥用快速排序实现?
对于快速排序来 说,数据是顺序访问的。而对于堆排序来说,数据是跳着访问的。
在排序过程中,堆排序算法的数据交换次数 要多于快速排序。
vector/list/deque 的区别与联系
数组,双向链表,双端数组。
个人理解,deque是将几个小vector用list的方式首位相连。
Stack 和 queue 不用 vector 实现的原因:容量大小有限制,扩容耗时。
为何关联容器的插入效率一般比其他序列容器高
关联容器不需要做内存拷贝和内存移动。
插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。
为什么 vector 的插入操作可能会导致迭代器失效?因为开辟了新空间。
unordered_map 和 map 的实现机制, 性能差异
实现机制: map 的内部实现是二叉平衡树(红黑树),有序 unordered_map 的实现是哈希表;无序
运行效率方面:unordered_map 高。 最差情况下,unordered_map 的查找效率会退化成 O(N)
占用内存方面: unordered_map 较低,map 占用最高。
set/map 的区别与联系
联系:底层都为红黑树
区别,set一个key,map有key和value,set 不能直接改变元素值。
set,map和vector的插入复杂度:log(N) ,O(1),O(N)
不允许有遍历行为的容器: queue stack heap
迭代器删除元素的话,会发生什么?
关联容器,删除当前iterator,仅仅会使当前的 iterator 失效,
序列式容器,vector,deque删除当前的 iterator 会使后面所有元素的iterator 都失效。
STL源码中的hash表的实现
哈希函数生成唯一的哈希值,通过对比哈希值确定元素值。
Hash 表的数据结构(解决哈希冲突的办法):
链地址法(Chaining)开放寻址法(Open Addressing)等。
map 中[ ] 和 find count的区别?
运算符[ ]:用下标查找,返回对应的值;不存在就将将其插入map。
find 函数:用关键码查找,找到返回该位置的迭代器;不存在就返回尾迭代器。
count函数:使用count,返回被查找元素的个数。如果有,返回1; 否则,返回0。