map 、set、multiset、multimap 底层原理及其相关面试题
(1)map 、set、multiset、multimap的底层原理
map 、set、multiset、multimap的底层实现都是红黑树,epoll模型的底层数据结构也是红黑树,linux系统中CFS进程调度算法,也用到红黑树。
红黑树的特性:
- 每个结点或是红色或是黑色;
-
根结点是黑色;
-
每个叶结点是黑的;
-
如果一个结点是红的,则它的两个儿子均是黑色;
-
每个结点到其子孙结点的所有路径上包含相同数目的黑色结点。
红黑树详解具体看这篇:别再问我什么是红黑树了
对于STL里的map容器,count方法与find方法,都可以用来判断一个key是否出现,mp.count(key) > 0统计的是key出现的次数,因此只能为0/1,而mp.find(key) != mp.end()则表示key存在。
(2)map 、set、multiset、multimap的特点
set和multiset会根据特定的排序准则自动将元素排序,set中元素不允许重复,multiset可以重复。
map和multimap将key和value组成的pair作为元素,根据key的排序准则自动将元素排序(因为红黑树也是二叉搜索树,所以map默认是按key排序的),map中元素的key不允许重复,multimap可以重复。
map和set的增删改查速度为都是logn,是比较高效的。
(3)为何map和set的插入删除效率比其他序列容器高,而且每次insert之后,以前保存的iterator不会失效?
因为存储的是结点,不需要内存拷贝和内存移动。
因为插入操作只是结点指针换来换去,结点内存没有改变。而iterator就像指向结点的指针,内存没变,指向内存的指针也不会变。
(4)为何map和set不能像vector一样有个reserve函数来预分配数据?
因为在map和set内部存储的已经不是元素本身了,而是包含元素的结点。也就是说map内部使用的Alloc并不是map<Key, Data, Compare, Alloc>声明的时候从参数中传入的Alloc。
(5)map 、set、multiset、multimap的常用函数
it map.begin() 返回指向容器起始位置的迭代器(iterator)
it map.end() 返回指向容器末尾位置的迭代器
bool map.empty() 若容器为空,则返回true,否则false
it map.find(k) 寻找键值为k的元素,并用返回其地址
int map.size() 返回map中已存在元素的数量
map.insert({int,string}) 插入元素
for (itor = map.begin(); itor != map.end();)
{
if (itor->second == "target")
map.erase(itor++) ; // erase之后,令当前迭代器指向其后继。
else
++itor;
}
评论(2)
map.erase(itor++) 这里有错吧,不需要++,直接itor=map.erase(itor)
我没注意到这是关联式容器,不好意思,搞错了