有序的关联容器:
底层数据结构:
红黑树 : 数据排好序的 非常适合查找 二分查找像是中序遍历一棵红黑树
时间复杂度是log(2 n)
LR不变,V变换位置 L左 R又 V根
前序遍历:VLR
中序遍历:LVR
后序遍历:LRV
前序遍历:VLR
中序遍历:LVR
后序遍历:LRV
set 集合
multiset多重集合
map 映射
multimap多重映射
multiset多重集合
map 映射
multimap多重映射
无序的关联容器:
底层数据结构:
哈希表(链地址法、拉链表)
增删的时间复杂度:接近O(1),
(为什么是接近O(1)?因为哈希冲突无法完全避免)
(为什么是接近O(1)?因为哈希冲突无法完全避免)
unordered_set
unordered_multiset
unordered_map
unordered_multimap
unordered_multiset
unordered_map
unordered_multimap
除留余数法:键值=value % 桶的个数 建议桶的个数为素数 这样可以更散列一点
解决哈希冲突:
1.线性探测法:
如果当前桶被占用,就去占用的下一个空闲的桶:(这样会增大哈希冲突的概率,也就意味着哈希表的增删查效率降低)
解决哈希冲突:
1.线性探测法:
如果当前桶被占用,就去占用的下一个空闲的桶:(这样会增大哈希冲突的概率,也就意味着哈希表的增删查效率降低)
负载因子:已用的桶/所有的桶 如果比值大于0.75 那么将给哈希表扩容。
2.链地址法:如果键值一样,就将这些数据组成一个链表挂在同一个桶的后面
(冲突太大,最终查找数据会变成遍历链表,也会使得查找不方便,效率会下降)
应用特点:快速的增删查,但是哈希表的数据是无序的,非常不适合范围查找
建议:80-90%都是使用哈希表,只有应用场景中需要数据有序,范围查找的时候,才会用红黑树实现的有序关联容器
建议:80-90%都是使用哈希表,只有应用场景中需要数据有序,范围查找的时候,才会用红黑树实现的有序关联容器
1、不同容器的特点
map 容器中的关键字是有序非重复的,每个元素类型是pair类型(《C++ Primer》第5版 p379),是一个key-malue对,关键字起到索引的作用,值则表示与索引相关联的数据
multimap 允许容器中的关键字是重复的
unordered_map 容器中的关键字是无序的
unordered_multimap 无序、允许重复关键字的容器
set 容器中的关键字是有序非重复的,与map不同,set中只有关键字,其他一样
multiset
unordered_set
unordered_multiset
2、容器选择原则
(1)先选择主要类型map还是set,如果只需要关键字,选择set,否则选择map;
(2)根据是否要求无序或重复进一步选择。
3、容器通用操作(以map为例,set类似)
(1)构造函数
map m1; m1是一个空map,它潜在的元素是T类型的,执行默认初始化
map m2(m1); m2中包含有m1所有元素的副本,m2与m1的T必须相同
map m2 = m1; 等价于m2(m1),复制初始化
map m3{a,b,c...}; m5包含了右边列表中的元素
map m3 = {a,b,c...}; 等价于m5{a,b,c...},复制初始化
map m4(b,e); 将迭代器b、e指定范围内的元素拷贝到m6
(2)访问
range for语句
迭代器
下标m[k] 返回关键字为k的元素,如果k不在m中,则会自动添加一个关键字为k的元素,并进行值初始化。
下标m.at(k) 同上,但是若k不在m中,将抛出一个out_of_range异常
注意,下标的含义是通过关键字获取值,set只有关键字,multimap和unordered_multimap有多个值与关键字相关联,所以只有map和unordered_map可以使用下标。
m.count(k) 返回关键字为k的元素的数量
m.lower_bound(k) 返回一个迭代器,指向第一个关键字不小于k的元素
m.upper_bound(k) 返回一个迭代器,指向第一个关键字大于k的元素
m.equal_range(k) 返回一个迭代器pair,表示关键字等于k的范围,若k不存在,pair的两个成员均等于m.end()
(3)插入
m.insert(v) 拷贝插入元素v,对于mat和set,函数返回插入是否成功的bool值,对于multi*,返回指向新元素的迭代器
c.emplace(args) 构造插入args表示的元素
m.insert(b,e) b和e是迭代器,表示一个key-value类型值的范围
m.insert(i1) 插入花括号列表i1中的元素
m.insert(p,v) 拷贝插入元素v,但是迭代器p仅作为一个提示,指出从哪里开始搜索新元素应该存放的位置
m.emplace(p,args) 构造插入args表示的元素
(4)删除
m.earse(k) 删除每个关键字为k的元素,返回删除的元素的数量:0、1、大于1
m.earse(p) 删除迭代器p指定的元素,p必须指向一个真实元素,不能是m.end()
m.earse(b,e) 删除迭代器b和e所指定范围的元素,返回e
(5)获取迭代器
begin()、end()、cbegin()、cend()、rbegin()、rend()、crbegin()、crend()(c表示const迭代器,r表示反向迭代器)
(6)类型别名
iterator、const_iterator、remerse_iterator、const_remerse_iterator、
size_type、difference_type、malue_type、reference、const_reference、
key_type、mapped_type(只适用于map)、value_type(对于set,与key_type相同,对于map,为pair类型)
4、无序关联容器
有序关联容器中的关键字是有序排列的,所以要求关键字可以进行<运算符比较或满足自定义的比较操作。无序关联容器不是使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符。
无序容器可以使用上述所有的与有序容器相同的操作,由于无序容器在存储上组织为桶,每个桶保存零个或多个元素,容器的性能依赖于哈希函数的质量和桶的数量和大小,因此无序容器多了一些哈希函数和桶相关的操作。
(1)桶接口
m.bucket_count() 正在使用的桶的数目
m.max_bucket_count() 容器能容纳的最多的桶的数量
m.bucket_size(n)
map 容器中的关键字是有序非重复的,每个元素类型是pair类型(《C++ Primer》第5版 p379),是一个key-malue对,关键字起到索引的作用,值则表示与索引相关联的数据
multimap 允许容器中的关键字是重复的
unordered_map 容器中的关键字是无序的
unordered_multimap 无序、允许重复关键字的容器
set 容器中的关键字是有序非重复的,与map不同,set中只有关键字,其他一样
multiset
unordered_set
unordered_multiset
2、容器选择原则
(1)先选择主要类型map还是set,如果只需要关键字,选择set,否则选择map;
(2)根据是否要求无序或重复进一步选择。
3、容器通用操作(以map为例,set类似)
(1)构造函数
map m1; m1是一个空map,它潜在的元素是T类型的,执行默认初始化
map m2(m1); m2中包含有m1所有元素的副本,m2与m1的T必须相同
map m2 = m1; 等价于m2(m1),复制初始化
map m3{a,b,c...}; m5包含了右边列表中的元素
map m3 = {a,b,c...}; 等价于m5{a,b,c...},复制初始化
map m4(b,e); 将迭代器b、e指定范围内的元素拷贝到m6
(2)访问
range for语句
迭代器
下标m[k] 返回关键字为k的元素,如果k不在m中,则会自动添加一个关键字为k的元素,并进行值初始化。
下标m.at(k) 同上,但是若k不在m中,将抛出一个out_of_range异常
注意,下标的含义是通过关键字获取值,set只有关键字,multimap和unordered_multimap有多个值与关键字相关联,所以只有map和unordered_map可以使用下标。
由于使用下标操作m[k]会使一个关键字不在m中的元素被添加进去,所以不能用下标来检测一个元素是否存在,因此关联容器定义了下面的一些查找操作。
m.count(k) 返回关键字为k的元素的数量
m.lower_bound(k) 返回一个迭代器,指向第一个关键字不小于k的元素
m.upper_bound(k) 返回一个迭代器,指向第一个关键字大于k的元素
m.equal_range(k) 返回一个迭代器pair,表示关键字等于k的范围,若k不存在,pair的两个成员均等于m.end()
(3)插入
m.insert(v) 拷贝插入元素v,对于mat和set,函数返回插入是否成功的bool值,对于multi*,返回指向新元素的迭代器
c.emplace(args) 构造插入args表示的元素
m.insert(b,e) b和e是迭代器,表示一个key-value类型值的范围
m.insert(i1) 插入花括号列表i1中的元素
m.insert(p,v) 拷贝插入元素v,但是迭代器p仅作为一个提示,指出从哪里开始搜索新元素应该存放的位置
m.emplace(p,args) 构造插入args表示的元素
(4)删除
m.earse(k) 删除每个关键字为k的元素,返回删除的元素的数量:0、1、大于1
m.earse(p) 删除迭代器p指定的元素,p必须指向一个真实元素,不能是m.end()
m.earse(b,e) 删除迭代器b和e所指定范围的元素,返回e
(5)获取迭代器
begin()、end()、cbegin()、cend()、rbegin()、rend()、crbegin()、crend()(c表示const迭代器,r表示反向迭代器)
(6)类型别名
iterator、const_iterator、remerse_iterator、const_remerse_iterator、
size_type、difference_type、malue_type、reference、const_reference、
key_type、mapped_type(只适用于map)、value_type(对于set,与key_type相同,对于map,为pair类型)
4、无序关联容器
有序关联容器中的关键字是有序排列的,所以要求关键字可以进行<运算符比较或满足自定义的比较操作。无序关联容器不是使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符。
无序容器可以使用上述所有的与有序容器相同的操作,由于无序容器在存储上组织为桶,每个桶保存零个或多个元素,容器的性能依赖于哈希函数的质量和桶的数量和大小,因此无序容器多了一些哈希函数和桶相关的操作。
(1)桶接口
m.bucket_count() 正在使用的桶的数目
m.max_bucket_count() 容器能容纳的最多的桶的数量
m.bucket_size(n)