C++STL之map和set的使用
Posted 小赵小赵福星高照~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++STL之map和set的使用相关的知识,希望对你有一定的参考价值。
map和set
文章目录
set
set的使用
set的插入
#include<iostream>
#include<set>
using namespace std;
void test_set1()
set<int> s;
s.insert(3);
s.insert(1);
s.insert(4);
s.insert(3);
s.insert(7);
int main()
test_set1();
return 0;
set的遍历
//遍历:排序+去重
set<int>::iterator it = s.begin();
while (it != s.end())
cout << *it << " ";
++it;
cout << endl;
//范围for遍历
for (auto e : s)
cout << e << " ";
cout << endl;
set<int> copy(s);//拷贝构造
for (auto e : s)
cout << e << " ";
set的find接口
#include<set>
void test_set()
set<int> s;
s.insert(4);
s.insert(2);
s.insert(3);
s.insert(6);
s.insert(1);
s.insert(8);
set<int>::iterator ret = s.find(4);// O(logN)
//这两个有效率的区别
auto ret = find(s.begin(),s.end(),4);//这个是暴力查找,在一段迭代器区间里进行查找 O(N)
find我们可以用算法里面的find接口,也可以用set提供的find接口:
set<int>::iterator ret = s.find(4);//O(logN)
//这两个有效率的区别
auto ret = find(s.begin(),s.end(),4);//这个是暴力查找,在一段迭代器区间里进行查找 O(N)
但是这两个有效率的区别:set的底层是二叉搜索树的性质,时间复杂度为O(logN),而算法当中的find是在一段迭代器区间暴力查找,在一段迭代器区间里进行查找,时间复杂度O(N)
set的erase接口
删除接口可以传迭代器撒谎才能胡,也可以传val,也可以传迭代器区间
- ```cpp
#include
void test_set()
set s;
s.insert(4);
s.insert(2);
s.insert(3);
s.insert(6);
s.insert(1);
s.insert(8);
set::iterator it = s.begin();
while(it!=s.end())
cout<<*it<<" “;
++it;
cout<<endl;
set::iterator ret = s.find(4);// O(logN)
if(ret != s.end())
s.erase(ret);
//也可以这样删除
s.erase(6);
s.erase(60);
for(auto e:s)
cout<< e <<” ";
cout<<endl;
int main()
test_set();
return 0;
map的介绍
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:
typedef pair value_type;- 在内部,map中的元素总是按照键值key进行比较排序的。
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行
直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。
SGI-STL中关于键值对的定义:template <class T1, class T2> struct pair typedef T1 first_type; typedef T2 second_type; T1 first; T2 second; pair(): first(T1()), second(T2()) pair(const T1& a, const T2& b): first(a), second(b) ;
map
map的使用
map的模板参数
key: 键值对中key的类型
T: 键值对中value的类型
Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器
注意:在使用map时,需要包含头文件。
map的插入
void test_map1
map<int,int> m;
m.insert(pair<int,int>(1,1));
m.insert(pair<int,int>(2,2));
m.insert(pair<int,int>(3,3));
我们在插入时需要这样插入,为什么呢?
我们可以看到insert函数有一个参数,类型是value_type,value_type被typedef成了pair,用键值对来存储数据,我们也可以这样:
m.insert(make_pair(4,4));//函数模板去构造匿名对象返回,这个不需要写模板参数,自动去推
make_pair的实现:
template<class T1,class T2>
pair<T1,T2> make_pair(T1 x,T2 y)
return (pair<T1,T2>(x,y));
那么为什么要将key和value封装起来呢?我们看下面的代码进行解释:
void test_map1
map<int,int> m;
m.insert(pair<int,int>(1,1));
m.insert(pair<int,int>(2,2));
m.insert(pair<int,int>(3,3));
map<int,int>::iterator it = m.begin();
while(it != m.end())
cout<<*it<<" ";//这里编译不过,这里如果这样的话需要返回两个值key和value,而C++不支持返回两个值,要返回两个值就需要构成一个结构来返回
++it;
cout<<endl;
*cout<<it<<endl;这里编译不过,这里如果这样的话需要返回两个值key和value,而C++不支持返回两个值,要返回两个值就需要构成一个结构来返回
所以需要这样用:
void test_map1()
map<int,int> m;
m.insert(pair<int,int>(1,1));
m.insert(pair<int,int>(2,2));
m.insert(pair<int,int>(3,3));
map<int,int>::iterator it = m.begin();
while(it != m.end())
//cout<<(*it).first << ":" << (*it).second << endl;
//operator* 返回的是节点中值的引用
cout<<it->first<<":"<<it->second<<endl;//这里为了可读性省略了一个箭头
//operator-> 返回的是节点中值的指针,也就是pair<k,v>*
++it;
cout<<endl;
也支持范围for遍历:
void test_map1()
map<int,int> m;
m.insert(pair<int,int>(1,1));
m.insert(pair<int,int>(2,2));
m.insert(pair<int,int>(3,3));
for(auto& e:m)
cout<<e.first<<":"<<e.second<<endl;
cout<<endl;
简单英文翻译字典
#include<map>
void test_map2()
map<string,string> dict;
dict.insert(pair<string,string>("sort","排序"));
dict.insert(make_pair("left","左边"));
dict.insert(make_pair("string","字符串"));
dict.insert(make_pair("right","右边"));
dict.insert(make_pair("bed","床"));
map<string,string>::iterator it = dict.begin();
while(it !=dict.end())
//it.operator*(),不能返回两个值,这里返回的是类对象
//cout<<(*it).first<<" "<<(*it).second<<endl;//报错
//it.operator->(),返回类对象指针
cout<<it->first<<" "<<it->second<<endl;
++it;
int main()
test_map2();
return 0;
统计字符串个数
void test_map3()
string str[] = "sort","sort","tree","insert","sort","tree","sort","test";
map<string,int> countMap;//统计字符串个数
for(auto& e:str)
auto ret = countMap.fin1d(e);//返回一个迭代器
if(ret == countMap.end())
//如果不存在,则插入
countMap.insert(make_pair(e,1));
//countMap.insert(pair<>(e,1));
else
//如果存在,则次数++
//(*ret).second++;
ret->second++;
for(auto& kv:countMap)
cout<<kv.first<<" "<<kv.second<<endl;
可以看到次数已经成功统计出来
统计次数的方式二:
正常来说如果insert插入成功了返回true,已经存在此时插入失败了返回false,但是我们可以看到insert的返回值是一个pair:
返回值是pair,其成员pair::first被设为一个迭代器,指向新插入的元素否则指向map中具有相等key的元素,如果插入了新元素,则将该对中的第二个元素pair::second设置为true;否则如果已经存在相等的key,则将其设置为false。
void test_map4()
string str[] = "sort","sort","tree","insert","sort","tree","sort","test" ;
map<string, int> countMap;
for (const auto& e : str)
//先插入,如果str在map中,insert会返回str所在的节点的迭代器,++次数即可
pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(e, 1));
//auto ret = countMap.insert(make_pair(e, 1));
if (ret.second == false)
//说明插入失败了,之前已经插入过了
ret.first->second++;//ret.first是指向相同key的那个元素的迭代器,ret是insert返回的pair
map<string, int>::iterator it = countMap.begin();
while (it != countMap.end())
cout << it->first << " " << it->second << endl;
++it;
operator[]的使用
统计次数的方式三(operator[]):
operator[]的实现:
mapped_type& operator[](const key_type& k)
return (*((this->insert(make_pair(k,mapped_type()))).first)).second;//插入时的匿名对象默认值为0
operator[]的实现进行简化,也可以这样实现:
mapped_type& operator[](const key_type& k)
pair<iterator,bool> ret = insert(make_pair(k,mapped_type()));//插入时的匿名对象默认值为0
return ret.first->second;
这里也分两种情况:
- k在map中,insert插入失败,因为k已经有了,insert返回的pair会带出k在map中存储节点的迭代器,通过这个迭代器,我们可以拿到k对应的value值,进行返回。
- k不在map中,insert进行插入,插入的值是pair<k,value()>,insert返回新插入值节点的迭代器,通过这个迭代器,我们可以拿到k对应的value值,进行返回。
总结map的operator[]特征:
- k不存在时,插入默认构造函数生成缺省值的value的pair<k,v()>
- k存在时,返回k对应的value值
void test_map5()
string str[] = "sort","sort","tree","insert","sort","tree","sort","test" ;
map<string,int> countMap;
//[]的用法
for(const auto& e:str)
countMap[e]++;//countMap[]返回的是value
for(const auto& kv:countMap)
cout<<kv.first<<" "<<kv.second<<endl;
1、如果k不在map中,先插入<k,V()>,返回新插入节点中V对象的引用
2、如果k已经在map中,返回k所在节点中对应V对象的引用
关于[]的一些扩展学习:
void test_map6()
map<string,string> dict;
dict.insert(make_pair("sort","排序"));
dict["left"] = "左边";//插入+修改
dict["insert"];//插入
dict["insert"] = "插入";//已经存在所以只是修改
dict["left"] = "左边、剩余";//已经存在所以只是修改
第一个是插入+修改,因为刚开始没有则插入,[]返回的是value,所以赋值相当于将他修改了,第二个只是插入,第三个只是修改,因为insert已经存在了就没有再插入只是修改,第四个也已经存在,所以只是修改
注意:
key不能被修改,但是value是可以被修改的:
#include<map>
void test_map()
map<string,string> dict;
dict.insert(pair<string,string>("sort","排序"));
dict.insert(make_pair("left","左边"));
dict.insert(make_pair("string","字符串"));
dict.insert(make_pair("right","右边"));
dict.insert(make_pair("bed","床"));
map<string,string>::iterator it = dict.begin();
while(it 6-6:STL之map和set