STL库的map和set的使用
2017-11-12 14:01
363 查看
之前我们讲到过红黑树这个数据结构,STL库中还有两个非常重要的容器的底层是通过红黑树实现的,那就是map(图)和set(集合)。两者的表示上的区别在于,set存储的只是一个key,而map是以key和value的方式存储的(实际上是存储了一个pair的键值对,后面会讲到)。两者的接口基本类似,为了方便起见,这里就以set为准先来介绍。
一.成员函数
与所有容器一样的是,set也有它自己的构造函数,析构函数,以及赋值运算符重载。
二.迭代器
同样的,它也有属于自己的迭代器。begin返回容器中第一个元素的迭代器,end返回容器中跟随最后一个元素的理论元素的迭代器,rbegin返回容器中的最后一个元素的反向迭代器,rend返回容器中第一个元素之前的理论元素的迭代器。测试代码如下:
正向迭代器的测试结果如下
反向迭代器的测试结果如下
三.和容量相关的接口
empty判断set是否为空,size返回set的中元素的个数,max_size返回容器可以容纳的最大元素数,这三者的测试代码如下:
测试结果如下
四.关于集合内部结构的修改器
insert
有三种形式的插入,其中最常用的是第一、二种插入。第一种insert,它返回一个键值对pair,首先它将返回pair的第一个元素迭代器,指向新插入的元素的迭代器或是该元素已经存在指向该元素的迭代器,其次返回pair的第二个元素bool值,如果插入成功返回true,该元素失败则返回false,上面代码的insert用的都是这一种。第二种返回指向插入元素的迭代器,如果集合中已经有这个元素,则返回该元素位置的迭代器。第三种insert不常用,这里暂不作详解。
测试代码如下:
erase
erase也有三种,第一种就是直接删除该位置上的元素,没有返回值;第二种删除返回删除元素的数量;第三种是删除first到last这一段区间上的元素。
下面是测试代码:
第一次删除后
第二次删除后
第三次删除后
swap
和另外一个set交换内容,这个很简单,就不测试了。
clear
清空集合
五.操作接口
find
查找元素,找到的话返回该元素的迭代器,找不到的话返回NULL
测试结果如下
count
计算集合中某一个特定元素的个数,因为集合中不会出现相同的元素,所以该接口只能返回1或0,经常用来判断集合中一个元素在不在,这里不作测试了。
lower_bound 和 upper_bound
lower_bound返回第一个元素的迭代器,它不认为是在val之前的。也就是说,如果我们给5,那么我们返回的就是5的迭代器(5之前的指比5小的)。
upper_bound返回第一个元素的迭代器,它是在val之后的。。也就是说,如果我们给5,那么我们返回的就是6的迭代器(6是5之后的第一个元素)。
测试代码如下:
两者的测试结果分别如下图
equal_range
返回一组范围的键值对
该范围最多只返回包括val在内的一个元素,如果val不存在则返回0,具体的我们直接看代码。
在这里我们为什么用pair,不用K,V呢?pair类型到底是一个怎样的类型呢?
pair的具体形式可以用下面的代码来描述
它的first是K类型,second是V类型。在迭代器取数据时返回值要求同时返回两个值,但是C++中一个函数只能返回一个值,所以存储类型要用pair。
map内的接口set差不多,我们先总体来看一下再看一下它们的区别
在这里基本上的接口都一样,最主要的区别就是map多了一个接口是operator[],这个接口的用处非常广泛。它的参数是key,返回值是value的引用。实际上它实现的就是下面的代码
我们将上述代码分开来看一下
①.
这一部分创建了一个pair对象,它的first是key,second是value的类型的缺省值,然后是在当前的map对象中插入这个pair对象
②.
第二部分取出了pair的first,并对first进行解引用取到它的值,我们就取到了关键字是key的这个对象
③.
第三部分,取出关键字为key这个对象的second,也就是value,之后的返回值也就是value的引用。
在插入的时候,如果map中没有要插入的key值,则插入一个key,value为V的类型的缺省值的pair对象,并返回对value的引用。如果map中已经有key这个关键字,则会直接返回value的引用。具体的测试代码如下:
如上,关键字west的value给的是缺省的,对于字符串而言,其缺省值就是NULL。另外在第二次插入student关键字时,又对它的value重新进行了赋值,我们可以通过监视窗口来发现两者的变化。
下面是第二个student插入前的窗口
下面是第二个student插入后的窗口
map和set都是用的非常广泛的容器,对于这两个容器的使用必须熟练掌握。
aaf8
set
set(集合)是按特定顺序存储独特元素的容器。在集合中,元素的值也标识它本身,也就是说,存储的就是key本身,每个值都必须是唯一的。集合中的元素不能修改,但是可以增加和删除。它的底层是以红黑树作为数据结构来实现的。下面我们来研究一下它的结构与接口。一.成员函数
与所有容器一样的是,set也有它自己的构造函数,析构函数,以及赋值运算符重载。
二.迭代器
同样的,它也有属于自己的迭代器。begin返回容器中第一个元素的迭代器,end返回容器中跟随最后一个元素的理论元素的迭代器,rbegin返回容器中的最后一个元素的反向迭代器,rend返回容器中第一个元素之前的理论元素的迭代器。测试代码如下:
void Testset() { int a[] = { 5, 6, 1, 9, 8, 3, 4, 2, 7, 0 }; set<int> s; for (size_t i = 0; i < sizeof(a) / sizeof(int); ++i) { s.insert(a[i]); } set<int>::iterator it=s.begin(); while (it != s.end()) { cout << *it << " "; it++; } /*set<int>::reverse_iterator rit = s.rbegin(); while (rit != s.rend()) { cout << *rit << " "; rit++; }*/ }
正向迭代器的测试结果如下
反向迭代器的测试结果如下
三.和容量相关的接口
empty判断set是否为空,size返回set的中元素的个数,max_size返回容器可以容纳的最大元素数,这三者的测试代码如下:
void Testset() { int a[] = { 5, 6, 1, 9, 8, 3, 4, 2, 7, 0 }; set<int> s; int b , size , maxsize = 0; b = s.empty(); size = s.size(); maxsize = s.max_size(); cout << b << " " << size << " " << maxsize << " "; for (size_t i = 0; i < sizeof(a) / sizeof(int); ++i) { s.insert(a[i]); } b = s.empty(); size = s.size(); maxsize = s.max_size(); cout << b << " " << size << " " << maxsize << " "; }
测试结果如下
四.关于集合内部结构的修改器
insert
有三种形式的插入,其中最常用的是第一、二种插入。第一种insert,它返回一个键值对pair,首先它将返回pair的第一个元素迭代器,指向新插入的元素的迭代器或是该元素已经存在指向该元素的迭代器,其次返回pair的第二个元素bool值,如果插入成功返回true,该元素失败则返回false,上面代码的insert用的都是这一种。第二种返回指向插入元素的迭代器,如果集合中已经有这个元素,则返回该元素位置的迭代器。第三种insert不常用,这里暂不作详解。
测试代码如下:
void Testset2() { int a[] = { 5, 6, 1, 9, 8, 3, 4, 2, 7, 0 }; set<int> s; 4000 s.insert(s.begin(), a[0]);//第二种插入 for (size_t i = 1; i < sizeof(a) / sizeof(int); ++i) { s.insert(a[i]);//第一种插入 } set<int>::iterator it = s.begin(); while (it != s.end()) { cout << *it << " "; it++; } }
erase
erase也有三种,第一种就是直接删除该位置上的元素,没有返回值;第二种删除返回删除元素的数量;第三种是删除first到last这一段区间上的元素。
下面是测试代码:
void Testset2() { int a[] = { 5, 6, 1, 9, 8, 3, 4, 2, 7, 0 }; set<int> s; for (size_t i = 0; i < sizeof(a) / sizeof(int); ++i) { s.insert(a[i]);//第一种插入 } s.erase(s.begin());//第一种删除,删除了0 s.erase(1);//第二种删除,删除了1 s.erase(s.begin(), s.end());//第三种删除,删除了set内的所有元素 set<int>::iterator it = s.begin(); while (it != s.end()) { cout << *it << " "; it++; } }
第一次删除后
第二次删除后
第三次删除后
swap
和另外一个set交换内容,这个很简单,就不测试了。
clear
清空集合
五.操作接口
find
查找元素,找到的话返回该元素的迭代器,找不到的话返回NULL
void Testset() { int a[] = { 5, 6, 1, 9, 8, 3, 4, 2, 7, 0 }; set<int> s; for (size_t i = 0; i < sizeof(a) / sizeof(int); ++i) { s.insert(a[i]); } set<int>::iterator it=s.begin(); it=s.find(5); //it=s.finf(10); //cout<<*it; while (it != s.end()) { cout << *it << " "; it++; } }
测试结果如下
count
计算集合中某一个特定元素的个数,因为集合中不会出现相同的元素,所以该接口只能返回1或0,经常用来判断集合中一个元素在不在,这里不作测试了。
lower_bound 和 upper_bound
lower_bound返回第一个元素的迭代器,它不认为是在val之前的。也就是说,如果我们给5,那么我们返回的就是5的迭代器(5之前的指比5小的)。
upper_bound返回第一个元素的迭代器,它是在val之后的。。也就是说,如果我们给5,那么我们返回的就是6的迭代器(6是5之后的第一个元素)。
测试代码如下:
void Testset() { int a[] = { 5, 6, 1, 9, 8, 3, 4, 2, 7, 0 }; set<int> s; for (size_t i = 0; i < sizeof(a) / sizeof(int); ++i) { s.insert(a[i]); } set<int>::iterator it=s.begin(); it = s.lower_bound(5); //it = s.upper_bound(5); while (it != s.end()) { cout << *it << " "; it++; } }
两者的测试结果分别如下图
equal_range
返回一组范围的键值对
该范围最多只返回包括val在内的一个元素,如果val不存在则返回0,具体的我们直接看代码。
void Testset() { int a[] = { 5, 6, 1, 9, 8, 3, 4, 2, 7, 0 }; set<int> s; for (size_t i = 0; i < sizeof(a) / sizeof(int); ++i) { s.insert(a[i]); } pair<set<int>::iterator, set<int>::iterator> ret; ret = s.equal_range(1); //ret= s.equal_range(10); cout << "the lower bound points to: " << *ret.first << endl; cout << "the upper bound points to: " << *ret.second << endl; }
map
map(图,也称映射)是由键值和映射值组合而成的存储元素的关联容器,遵循特定的顺序。在map中,键值通常用于排序和唯一标识元素(pair类型的first),而映射值存储与此键相关的内容(pair类型的second)。键和映射值的类型可能不同,并在成员类型value_type中组合在一起,这是一对组合的类型typedef pair<const Key, const Value> value_type;
在这里我们为什么用pair,不用K,V呢?pair类型到底是一个怎样的类型呢?
pair的具体形式可以用下面的代码来描述
template <class K,class V> struct pair { K first; V second; pair(const K* key, const V* value) :first(key) , second(value) {} };
它的first是K类型,second是V类型。在迭代器取数据时返回值要求同时返回两个值,但是C++中一个函数只能返回一个值,所以存储类型要用pair。
map内的接口set差不多,我们先总体来看一下再看一下它们的区别
在这里基本上的接口都一样,最主要的区别就是map多了一个接口是operator[],这个接口的用处非常广泛。它的参数是key,返回值是value的引用。实际上它实现的就是下面的代码
(*((this->insert(make_pair(k,mapped_type()))).first)).second
我们将上述代码分开来看一下
①.
this->insert(make_pair(k,mapped_type()))
这一部分创建了一个pair对象,它的first是key,second是value的类型的缺省值,然后是在当前的map对象中插入这个pair对象
②.
*(this->insert(make_pair(k,mapped_type()))).first)
第二部分取出了pair的first,并对first进行解引用取到它的值,我们就取到了关键字是key的这个对象
③.
(*((this->insert(make_pair(k,mapped_type()))).first)).second
第三部分,取出关键字为key这个对象的second,也就是value,之后的返回值也就是value的引用。
在插入的时候,如果map中没有要插入的key值,则插入一个key,value为V的类型的缺省值的pair对象,并返回对value的引用。如果map中已经有key这个关键字,则会直接返回value的引用。具体的测试代码如下:
void Testmap1() { map<string, string> m; m["student"] = "学生"; m["west"]; m["left"] = "左边"; m["right"] = "右边"; m["student"]= "老师"; }
如上,关键字west的value给的是缺省的,对于字符串而言,其缺省值就是NULL。另外在第二次插入student关键字时,又对它的value重新进行了赋值,我们可以通过监视窗口来发现两者的变化。
下面是第二个student插入前的窗口
下面是第二个student插入后的窗口
map和set都是用的非常广泛的容器,对于这两个容器的使用必须熟练掌握。
aaf8
相关文章推荐
- C++中防止STL中迭代器失效——map/set等关联容器——vector/list/deque等序列容器—如何防止迭代器失效—即erase()的使用
- 高效的使用stl::map和std::set
- STL------list、set、map的简单使用
- STL之关联容器(pair、map、set的使用)
- STL之std::set、std::map的lower_bound和upper_bound函数使用说明
- STL中list,vector,deque,map,set区别、联系和使用场景
- stl容器区别(内存布局和使用场合): vector list deque set map
- C++ STL容器的学习使用(vector、queue、list、set、map)
- STL之std::set、std::map的lower_bound和upper_bound函数使用说明
- STL中list,vector,deque,map,set区别、联系和使用场景
- C++中防止STL中迭代器失效__map/set等关联容器vector/list/deque等序列容器_如何防止迭代器失效_即erase()的使用
- C++ STL容器的使用方法(vector、queue、list、set、map)
- 使用linux的GDB打印STL(vector,map,set..................)
- STL中list,vector,deque,map,set区别、联系和使用场景原理
- 【STL】map与set的使用方法
- STL中list,vector,deque,map,set区别、联系和使用场景
- 《 set/map 的使用 ----STL》
- C/C++--STL中list,vector,deque,map,set区别、联系和使用场景
- STL中list,vector,deque,map,set区别、联系和使用场景
- [置顶] STL——set && map的使用