set与map是c++中两个主要的关联容器,map容器中的元素是一些关键字-值(key-value)对,而set容器保存的key值与value值是一样的,set保存的值就是关键字。
在set和map中每个关键字都是唯一的,若允许重复关键字,则在容器的名字前加上单词multi,故就有了multiset与multimap,而且系统能根据key值自动进行排序(默认是从小到大排序)。关联容器不支持位置操作例如:push_back,push_pop等,因为set以及map是根据关键字即key值存储的,而且关联容器也不支持构造函数或插入操作这些接受一个元素值和一个数量值得操作。
set与multiset包含在头文件#include<set>中;
map与multimap包含在头文件#include<map>中;
map:关键字起到索引的作用,值则表示索引的内容,例如:英汉字典中查去某个单词的意思,可以key表示索引该单词所在位置,value代表该单词的意思。
set:支持高效的关键词查询操作——检查一个关键字是否在set中,例如:一个企业可以定义一个名为bad_checks的set来保存那些曾经开过空头支票的人的名字。在接受一张支票之前可以查询bad_checkes来检查顾客的名字是否在其中。
map和set是二叉树结构
插入删除效率比其他容器高的原因是,插入和删除不需要内存拷贝和内存移动。每个元素都是以节点的方式存储的,其节点结构与链表(list)差不多,用指针指向。
在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。
一、set的使用方法:
1、set容器的构造和赋值
构造:set<T>st; 默认构造
set<T>st1(st); 拷贝构造
赋值:set& operator=(ocnst set &st); 重载等号操作符
set<int>st;
set<int>st2(st);
set<int>st3;
st3=st;
2、插入和删除
insert(elem); 在容器中插入数据
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int>st;
st.insert(10);
st.insert(10);
st.insert(50);
st.insert(30);
st.insert(20);
st.insert(60);
for (set<int>::iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
system("pause");
return 0;
}
这里可以看出set自动或略了重复值并且进行了从小到大排序。
clear(); 清除所有元素
erase(pos); 删除pos迭代器所指的元素,返回下一个元素的迭代器;
erase(beg,end); 删除区间[beg,end]的所有元素,返回下一个元素的迭代器
erase(elem); 删除容器中的值为elem的元素
使用如下:
st.clear();
st.erase(pos);
st.erase(beg,end);
st.erase(elem);
3、查找和统计
find(key); 查找key是否存在,若存在,返回该键元素的迭代器;
count(key); 统计key的元素个数,对于set容器而言要么是0要么是1;
st.find(key);
st.count(key);
4、大小和交换
size(); 返回容器中元素的个数
empty(); 判断容器是否为空
swap(); 交换两个容器
st.size();
st.empty();
st1.swap(st);
multiset没有重复检测,返回的是iterator,可以重复插入键值。
二、map的使用
介绍map容器之前先来介绍键值对;对于键值对的创建有两种方式:
1)pair<type,type>p(value1,value2);
2) pair<type,type>p=make_pair(value1,value2);
1、map的默认构造
map<T1,T2>mp; map的拷贝构造
map<<T1,T2>mp1(mp); map的拷贝构造
map& operator=(const map&map); 重载等号运算符
#include<iostream>
#include<map>
using namespace std;
int main()
{
map<int, int>mp;
map<int, int>mp1(mp);
map<int, int>mp2;
mp2 = mp;
system("pause");
return 0;
}
2、map容器的插入和删除
inset(); 在容器中插入数据,注:这里插入的不是单值而是键值对;
四种插入方式:
1)mp.insert(pair<T1,T2>(value1,value2));
2) mp.insert(make_pair(value1,value2));
3) mp.insert(map<T1,T2>::value_type(value1,value2));
4) m[key]=value;
#include<iostream>
#include<map>
using namespace std;
int main()
{
map<int, int>mp;
mp.insert(pair<int, int>(2, 20));
mp.insert(make_pair(1, 30));
mp.insert(map<int, int>::value_type(5, 10));
mp[4] = 50;
for (map<int, int>::iterator it = mp.begin(); it != mp.end(); it++)
{
cout << "key: " << it->first << " value:" << it->second << endl;
}
system("pause");
return 0;
}
键值自动进行排序
clear(); 清除所有元素
erase(pos); 删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); 删除[beg,end]区间的元素,返回下一个元素的迭代器
erase(key); 删除容器中key键值的元素
mp.clear();
mp.erase(pos);
mp.erase(beg,end);
mp.erase(key);
3、map的查找和统计
find(key); 查找key值是否存在,若存在返回该键值元素的迭代器,若不存在返回mp.end();
count(key); 统计key元素的个数
mp.find(key);
mp.count(key);
4、map的大小和交换
size(); 统计容器中的元素个数
empty(); 判断容器是否为空
swap(); 交换两容器
mp.size();
mp.empty();
mp1.swap(mp);
5、map容器的顺序操作
map默认是按照键值进行从小到大排序; 另一种就是用map的一种构造方式
map<T1,T2,函数>m; 这里的函数是仿函数
仿函数举例:仿函数就是对()的重载
#include<iostream>
#include<map>
using namespace std;
class myCompare
{
public:
bool operator()(int v1,int v2)const
{
return v1 > v2;
}
};
int main()
{
map<int, int>mp;
mp.insert(pair<int, int>(2, 20));
mp.insert(make_pair(1, 30));
mp.insert(map<int, int>::value_type(5, 10));
mp[4] = 50;
cout << "默认排序" << endl;
for (map<int, int>::iterator it = mp.begin(); it != mp.end(); it++)
{
cout << "key: " << it->first << " value:" << it->second << endl;
}
map<int, int, myCompare>mp1;
mp1.insert(make_pair(2, 20));
mp1.insert(make_pair(1, 30));
mp1.insert(make_pair(5, 10));
mp1.insert(make_pair(4, 50));
cout << "重载后" << endl;
for (map<int, int,myCompare>::iterator it = mp1.begin(); it != mp1.end(); it++)
{
cout << "key: " << it->first << " value:" << it->second << endl;
}
system("pause");
return 0;
}
multimap:可以有相同的键值;