map和set
目录
1、二叉搜索树
2、set
3、multiset
4、map
5、multimap
这里将会介绍二叉搜索树,以及与之相关的四种容器的使用和特性
1、二叉搜索树
二叉搜索树我认为还是比较简单的,所以不单独写一篇博客,而是在这里进行一些介绍
二叉搜索树又称二叉排序树或二叉查找树,它可以是一棵空树,如果不是空树那就具有一些性质:
若左子树不为空,则左子树上所有节点的值都小于根节点的值
若右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
由于二叉搜索树有这样的规律,所以用于搜索和查找时都会非常方便,对其中序遍历就可以进行升序排序。二叉搜索树有key模式和key-value模式,key模式就是树的每个节点都带有一个key值,而key-value模式就是每个节点在带有一个key值的同时还匹配一个value值,那么可以通过key值查找到对应的value值。这种结构也叫做键值对,键值对是用来表示具有一一对应关系的一种结构,比如在字典中通过查找单词就可以找到单词对应的中文意思,那么我们可以把单词看作是key值,把中文看作是对应的value值。
2、set
按照我的理解,set就可以被认为是存储key模式的搜索二叉树的容器,并且它在存储数据时会按照key的类型的比较方式对数据进行排序,set中的元素不能被修改,但是可以从容器中进行插入或者删除,set中的元素的key值是不可以重复的,在插入时也会进行自动去重,查找元素的时间复杂度为logN
可以看到set的模板参数列表中,T表示set中存放元素的类型,Compare表示set中元素的比较方式,默认按照升序来排列。Alloc是set中元素空间的管理方式,使用STL提供的空间适配器管理。对于空间适配器在后续也会进行学习和详细介绍,这里可以先不用管
根据之前的学习经验,set的用法也是差不多的包括set的构造、set的迭代器、set的插入删除等
set s;s.insert(4);s.insert(6);s.insert(8);s.insert(3);s.insert(5);s.insert(7);s.insert(7);s.insert(7);s.insert(7);set::iterator it = s.begin();while (it != s.end()){cout << *it <<\" \" ;it++;}cout << endl;for (auto& e : s){cout << e << \" \";}cout << endl;auto pos = s.find(3);s.erase(pos);s.erase(s.find(7));s.erase(5);for (auto& e : s){cout << e << \" \";}cout << endl;
不过还是有些特殊的地方的,count()函数,参数为需要寻找的元素值,返回值为0或1,可以找到就返回1,找不到就返回0。
迭代器:low和up可以用于指定边界位置,可以配合lower_bound(),upper_bound(),equal_range(),first,second一起使用
lower_bound():参数为需要寻找的左边界元素值,返回大于等于参数的元素值位置。
upper_bound():参数为需要寻找的有边界元素值,返回大于参数的元素值位置。
那么就可以将lower_bound()的返回值作为low的值,将upper_bound()的返回值作为up的值,就可以确定一个区间进行统一的删除操作。
还有equal_range(),参数为需要寻找的元素值,返回值为参数值相同的元素的位置区间,first为首位置,second为尾位置,将首尾位置赋值给low和up也可以确定区间并实现删除操作
set s;s.insert(4);s.insert(6);s.insert(8);s.insert(3);s.insert(5);s.insert(7);s.insert(7);s.insert(7);s.insert(7);//auto itlow=s.lower_bound(5);//auto itup=s.upper_bound(7);auto ret=s.equal_range(7);auto itlow = ret.first;auto itup = ret.second;cout << *itlow << endl;cout << *itup << endl;s.erase(itlow, itup);for (auto& e : s){cout << e << \" \";}cout << endl;
这里的count()、equal_range()看起来用处并不大,但实际他们是专门为multiset设计的,因为multiset和set使用的是同样的接口。
3、multiset
multiset大部分内容都与set一样,只是multiset里面的元素可以重复,那么count()就会返回查找到的参数的个数,而equal_range()是返回与参数值相同的位置区间
multiset s;s.insert(4);s.insert(6);s.insert(8);s.insert(3);s.insert(5);s.insert(7);s.insert(7);s.insert(7);s.insert(7);for (auto& e : s){cout << e << \" \";}cout << endl;//auto itlow=s.lower_bound(5);//auto itup=s.upper_bound(7);auto ret = s.equal_range(7);auto itlow = ret.first;auto itup = ret.second;cout << *itlow << endl;cout << *itup << endl;s.erase(itlow, itup);for (auto& e : s){cout << e << \" \";}cout << endl;
4、map
开头介绍了二叉搜索树有key模式和key_value模式,set是用于存储key模式的二叉搜索树容器,那么map就是用于存储key_value模式的二叉搜索树的容器。map中的first和second分别用于表示key值和value值
在map中,key值用于排序和标识元素,key是唯一的且不能被修改,map中的元素也是有序的,默认按照key的小于方式进行比较,key与value的类型可以不同,key与value通过成员类型value_type绑定在一起,为其取别名称为pair
在进行定义时不仅要显式定义map,还有显式定义pair,如果插入与map中已有元素的key值相同的元素,无论value值是否相同都不会进行插入,也不会进行覆盖
map dict;pair k1(\"insert\", \"插入\");dict.insert(k1);dict.insert(pair(\"erase\", \"删除\"));//c++98dict.insert(make_pair(\"string\", \"字符串\"));//c++11dict.insert({ \"find\",\"查找\" });auto it = dict.begin();while (it != dict.end()){cout << (*it).first << \":\" << (*it).second << endl;it++;}cout << endl;dict.insert(make_pair(\"string\", \"xxxxx\"));for (auto& k : dict){cout << k.first << \":\" << k.second << endl;}
map支持下标访问符,在[ ]中放入key,就可以找到与之相对应的value值
string arr[] = { \"西瓜\", \"西瓜\", \"苹果\", \"西瓜\", \"苹果\", \"苹果\", \"西瓜\", \"苹果\", \"香蕉\", \"苹果\", \"香蕉\" };map countMap;//for (auto e : arr)//{//auto it = countMap.find(e);//if (it!=countMap.end())//(*it).second++;//else//countMap.insert(make_pair(e, 1));//}for (auto e : arr){countMap[e]++;}for (auto& e : countMap){cout << e.first << \":\" << e.second << endl;}
而这里我们可以使用简单的[ ]就实现对水果进行插入并记录次数的原因在于operator[]的底层实现
这是operator[]的实现代码,首先会对key进行插入,并用pair类型来接收返回值,那么就会出现以下两种情况
并对节点的value值进行返回,因此如果这个key不在树里,那么operator[]会将其插入并返回value值,此时的value值为被初始化的值,由于是int类型所以初始值为0,当我们进行++操作那么就将value值变为1,再进行后续的循环时,首先会进行插入操作,但是由于key已经在树里面,则不进行插入,并返回key对应的value值,我们只需将其++就可以实现次数的对应了。
虽然map中的key值不可以被修改,但是value值是可以被修改的,并可以通过operator[]来实现
5、multimap
multimap与map大部分内容都是相同的,唯一的区别在于map中的key值不能重复,而multimap中的key值是可以重复的,正因如此,multimap中并没有重载operator[]操作