map
map释义“映射”,和set类似,是一个典型的有序关联容器,不同的是map是成对的(key,value)且一对一映射,一个key对应一个value,key不能重名,但value是不做限制的,而set只有key,map和set用法很类似,map中的元素由pair构成。
pair
pair释义“对”,也就是(key, value),本质上是一个只有两个元素的结构体,pair中的两个元素类型可以相同,也可以不同,两个元素的名字是固定的,前者叫first对应key,后者叫second对应value,要访问map中的key和value,就要先找到pair,然后找first和second。
构造函数
map<string,int> map1; // 默认构造函数
map<string,int> map2(map1.begin(),map1.end()); //范围构造函数
map<string,int> map3(map2); //拷贝构造函数
map<string,int> map4(move(map3)); //移动构造函数
map<int,string> map5{ {1,"hu"}, {2,"dai"}, {3,"zhou"} };//列表构造函数
元素访问
at() auto x=map5.at(1); //访问第一个元素value为“hu”
operator[ ] auto x = map5[3]; //访问key为3的value,为“zhou”
迭代器
迭代器和array的相同,不同是内部元素有2个,访问时要指定具体的哪一个
begin() & cbegin() cout<< map5.begin()-> second <<endl;//第一个元素
end() & cend() cout<< map5.end()-> second <<endl; //最后一个元素
容量
empty(): map1.empty(); //空查询
size() map1.size(); //素大小
max_size() map1.max_size(); //最多可以放的元素
修改器
insert(): map5.insert({1,"suai"}); //插入必须{ },key重复不理会。
insert_or_assign map5.insert_or_assign(1,"suai"); //不需要{ },替换value值。
multimap
multimap是map的升级,map的key不能重复,如果出现重复的插入直接不理会,但是有时候我们就是有重名的需求,如一个班级有同名的学生等,multimapt就是用来存储可以重名的key的有序关联容器。multimap和map非常相似,其相关的使用方法一样,简单的示例如下:
multimap<int,string> bb{ {1,"hu"}, {1,"dai"}, {1,"zhou"} };
for(auto x:bb)
{
cout<<x.first<<" "<<x.second<<endl;
}
cout<<endl;
无序关联容器
无序关联容器和有序关联容器很相似,都有set、map、multiset、multimap对应的名称,unordered_set、unordered_map,不同是set和map是有序的,底层使用红黑树实现,插入数据时会被排序,而unordered是无序的,底层是哈希函数实现的,插入时不会被排序,按照哈希规则直接映射存放。哈希函数是一类函数的统称,就像递归函数一样。
“桶”是哈希中的一个概念,unordered可以想象成一个房间有很多桶,桶中又装了很多的瓶装矿泉水,一个key就是一瓶水,装了很多桶的房间就是unordered容器。按照哈希规则来决定key被放入那个桶的什么位置。哈希函数就是一种映射规则,支持key的单独访问,总之就是key被放在哪里,是遵守一定规则的,同一个对象,每次被放入的位置时相同的。这个规则就叫哈希。
哈希函数和桶
哈希是英文hash的发音,全称是hashmap,是一种典型的数据结构,哈希表也被称为散列表。哈希表特点是用消耗内存的方法,来大幅度提高查找数据的时间,在STL中的hashmap就是unordered_map,哈希函数是用来实现哈希表的函数,是一类而不是一个。哈希表本质是k-v结构,可以通过key找到对应的value。
哈希碰撞
哈希碰撞也叫哈希冲突,是一种后面的数据覆盖前面的数据的现象,在使用哈希表时,假如我们以数字key来作为数组中的下标号,即下标为1就放在第1个位置,为50就放在第50个位置,问题来了,如果别人给了个1000那我们就要存放在第1000个位置去,也就是说不管我们给数组预留多大空间都有可能被越界访问,常规的做法就是将数字%x取余方法来作为下标,但是这样就会造成数据被覆盖,导致两难的局面,要么把数组留得很长,要么就人为避免数据碰撞。
闭链法
基于上面的问题,我们的解决方法可以是闭列法,也叫线性探测法,就是在插入的时候发现已经有了数据那么就自动往后移动一次插入,如果移动后还是有数据就再往后移动,直到找到空白。
开链法
开链法就是当检测到目标位置已经有数据就在他的下方再找一个区域去存放,用指针指向他,下面挂的这种东西就叫桶。看上去就是哈希表下面挂了很多东西,如下图。
由于unordered_map的使用和前面的map非常相似,所以不再重复,只是单独的把unordered_map的桶的使用单独拿出来讲一下,普通的建立和访问如下示例:
unordered_map<int,string> aa;
for(i=0;i<20;i++)
{
aa.insert({i,"aa"});
}
for(auto x:aa)
{
cout<< "{"<<x.first<<", "<<x.second<<" }"<<endl;
}