容器(Containers)
顺序容器
array [c++11]
vector
单开口,预留空间
emplace_back[c++11] 在最后构造并插入
list
容器适配器
stack
后进先出 使用deque/list,不用vector的原因应该是容量大小有限制,扩容耗时
queue
先进先出 使用deque/list,不用vector的原因应该是容量大小有限制,扩容耗时
deque
关联容器
set
map
multiset
multimap
无序关联容器
unordered_set [c++11]
unordered_map [c++11]
unordered_multiset [c++11]
unordered_multimap [c++11]
容器分类
数据结构
数组 array/vector
特点: 随机访问,vector删除数据时,空间不释放
双向链表 list
特点:快速增删
双端队列 deque
特点: 随机访问,头尾快速增删
红黑树 set/multiset map/multimap
特点:插入删除性能相同O(log2n)
哈希表 unordered_set/unordered_multiset unordered_map/unordered_multimap
特点: 最优O(1),最差O(n)
有序
红黑树
不可重复
哈希+红黑树
红黑树 R-B Tree,全称是Red-Black Tree 一种特殊的二叉查找树
红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
操作时间是:log n
AVL树-自平衡二叉查找树
特性:
(1)它的左子树和右子树都是AVL树
(2)左子树和右子树的高度差不能超过1
顺序容器常用操作
iterators | const iterators | capacity | element access | modifiers | observers |
---|---|---|---|---|---|
begin | cbegin | size | at | push_front | data |
end | cend | empty | [] | pop_front | |
rbegin | front | push_back | |||
rend | end | pop_back | |||
erase | |||||
swap | |||||
clean | |||||
insert |
关联容器 常用操作
operations | observers |
---|---|
count | key_comp |
find | value_comp |
算法(Algorithms)
头文件
只读算法
查找算法
函数 | 描述 |
---|---|
find(beg, end, v) | 在[beg, end)之间查找等于v的元素,找到返回迭代器,找不到返回end |
find_first_of(beg, end, beg2, end2) | 在[beg, end)之间查找[beg2, end2)内任意匹配元素,找到返回的第一个容器中第一个匹配的元素 |
find_end(beg, end, beg2, end2) | 找到最后匹配的元素 |
find_if(beg,end,func) | 函数find的带一个函数参数的_if版本,与find功能相同,条件:使函数func返回true |
搜索与统计算法
函数 | 描述 |
---|---|
search(beg, end, beg2, end2) | 在区间1内搜索子序列2 |
search_n(beg, end, n, v) | 在区间[beg, end)内查找连续n个元素v |
count(v) | 统计v的个数 |
lower_bound(beg, end, v) | 查找非递减序列,第一个大于v的元素 |
upper_bound(beg, end, v) | 查找非递减序列,第一个小于v的元素 |
count_if(beg, end, v) | 函数count的_if版本 |
可变序列算法
函数 | 描述 |
---|---|
copy(beg, end, beg2) | 将[beg, end)复制到beg2 |
transform(beg, end, beg2, func) | 将每个元素经过func |
replace(beg, end, v1, v2) | 将[beg, end)中的v1替换v2 |
fill(beg, end, v) | 将[beg, end)写入v |
fill_n(beg, n, v) | 从beg写入n个v |
generate(beg, n, rand) | 从beg,填入n个随机数 |
remove(beg, end) | 移除区间[beg, end)内元素,不是真正删除,只是移到最后 |
unique(beg, end) | 删除相邻重复元素,不是真正删除,只是移到最后 |
remove_if(beg, end, func) | remove的_if版本 |
replace_if(beg,end,func,v2) | replace的_if版本 |
remove_copy(beg,end,dest) | remove的_copy版本,将反转后的序列输出到从dest开始的区间。 |
排序算法
函数 | 描述 |
---|---|
sort(beg,end) | 字典排序 |
stable_sort(beg,end) | 字典排序。保存相等元素关系 |
parital_sort(beg,mid,end) | 取mid - beg最小元素,放入[beg,mid)内 |
random_shuffle(beg,end) | 随机排序 |
reverse(beg,end) | 翻转 |
rotate(beg,mid,end) | [beg,mid)和[mid,end)元素旋转,并使用mid作为起点 |
merge(beg,end,beg2,end2,nbeg) | 合并为一个,同时排序 |
reverse_cpoy(beg,end,dest) | reverse的copy |
rotate_cpoy(beg,mid,end,dest) | rotate的copy |
关系算法
函数 | 描述 |
---|---|
equal(beg,end,beg1,end1) | 判断两区间是否相同 |
include(beg1,end1,beg2,end2) | 判断[beg2,end2)是否包含[beg1,end1) |
max_element(beg,end) | 返回最大元素 |
min_eleament(beg,end) | 返回最小元素 |
mismatch(beg,end,beg1,end1) | 查找两序列,第一个不匹配的的元素,返回一对it |
堆算法
“堆”是个很有趣的数据结构,是个完全二叉树。
“堆”的特性:每个节点的键值一定总是大于(或小于)它的父节点(大于:称为“最大堆”,小于:称为“最小堆”),或者说每个节点总是大于或小于它的子节点。
对于最大堆而言,根节点为最大值;对于最小堆而言,根节点为最小值。
通常“堆”是通过数组来实现的,这样可以利用数组的特点快速定位指定索引的元素。
完全二叉树:对于一个树高为h的二叉树,如果其第0层至第h-1层的节点都满。如果最下面一层节点不满,则所有的节点在左边的连续排列,空位都在右边。这样的二叉树就是一棵完全二叉树。
函数 | 描述 |
---|---|
make_heap(beg,end) | 以区间[beg,end)建立堆 |
pop_heap(beg,end) | 重新排序堆,第一个和最后一个交换,并不弹出正在最大值 |
push_heap(beg,end) | 插入元素,重新排序堆 |
sort_heap(beg,end) | 对序列重新排序 |
容器特有的算法
因为list容器上的迭代器是双向的,所以不能使用随机访问的迭代器算法。
参考链接:
https://blog.csdn.net/xyqqwer/article/details/81263060
常见问题
STL有哪些组件?
容器,迭代器,算法,容器适配器
STL常用的容器有哪些以及各自的特点是什么?
说说std::vector的底层(存储)机制。
什么情况下用vector,什么情况下用list。
vector中begin和end函数返回的是什么?
为什么vector的插入操作可能会导致迭代器失效?
vector动态增加大小时,并不是在原空间后增加新的空间,而是以原大小的两倍在另外配置一片较大的新空间,然后将内容拷贝过来,并释放原来的空间。由于操作改变了空间,所以迭代器失效。
deque与vector的区别。
1)vector是单向开口的连续线性空间,deque是双向开口的连续线性空间。(双向开口是指可以在头尾两端分别做元素的插入和删除操作)。
2)deque没有提供空间保留功能,而vector则要提供空间保留功能。
3)deque也提供随机访问迭代器,但是其迭代器比vector迭代器复杂很多。
不允许有遍历行为的容器有哪些(不提供迭代器)
queue,stack,heap
说说std::map底层机制。
vector、list、map、deque用erase(it)后,迭代器的变化。
vector和deque是序列式容器,其内存分别是连续空间和分段连续空间,删除迭代器it后,其后面的迭代器都失效了,此时it及其后面的迭代器会自动加1,使it指向被删除元素的下一个元素。
list删除迭代器it时,其后面的迭代器都不会失效,将前面和后面连接起来即可。
map也是只能使当前删除的迭代器失效,其后面的迭代器依然有效。
map和set的3个问题。
1)为何map和set的插入删除效率比其他序列容器高。
因为不需要内存拷贝和内存移动
2)为何map和set每次Insert之后,以前保存的iterator不会失效?
因为插入操作只是结点指针换来换去,结点内存没有改变。而iterator就像指向结点的指针,内存没变,指向内存的指针也不会变。
3)当数据元素增多时(从10000到20000),map的set的查找速度会怎样变化?
RB-TREE用二分查找法,时间复杂度为log2n,所以从10000增到20000时,查找次数从log210000=14次到log220000=15次,多了1次而已。