容器set封装了集合的数据结构及操作。该容器实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树的根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值;另外,还得保证根节点左子树的高度与右子树高度相等。平衡二叉检索树使用中序遍历算法,检索效率高于vector、deque和list等容器,另外使用中序遍历可将键值按照从小到大遍历出来。
构造set集合主要目的是为了快速检索,不可直接去修改键值。
需要引用头文件:
#include <set>
1.1 定义
template <class Key,
classCompare=less<Key>,
classAlloc=STL_DEFAULT_ALLOCATOR(Key) >
比较函数对象及内存分配器采用的是默认参数,因此如果未指定,它们将采用系统默认方式。
若key的类型T为类或struct时,需要提供T的==和<的重载运算符。
struct IPLess {
public:
bool operator() (const char *s1, const char *s2)const {
return strcmp(s1, s2) < 0;
}
};
class IP {
int d1, d2, d3, d4;
public:
booloperator<(const IP& a) const {
return (d1 < a.d1)|| (d2 < a.d2) || (d3 < a.d3) || (d4 < a.d4);
}
booloperator==(const IP& a, const IP& b) const {
return(a.d1==b.d1)&&(a.d2 == b.d2)&&(a.d3 == b.d3)&&(a.d4 == b.d4);
}
}
创建set对象,有几种常用方式:
//创建空的set对象,元素类型为int
set<int> setInt;
//创建空的set对象,元素类型char*,比较函数对象(即排序准则)为自定义strLess
set<IP, IPComp> setIP;
//利用set对象s1,拷贝生成set对象s2
set<int>setInt2(setInt);
//用迭代区间[&first,&last)所指的元素,创建一个set对象
int iArray[] = {13, 32,19};
set<int> setInt3(iArray,iArray + 3);
//用迭代区间[&first,&last)所指的元素,及比较函数对象strLess,创建一个set对象
IP szArray[] = {IP(1,1,1,1), IP(2,2,2,2), IP(3,3,3,3)};
set<IP, IPComp> setIP(szArray, szArray + 3);
1.2 元素插入
使用insert函数插入数据,insert可返回pair<iterator, bool>,如果集合已有该数据,则失败并置返回值中bool为false;否则,bool为true,iterator指向刚插入数据的位置。Insert还可以一次插入[first, last)区间的多个数据,其中,first,last均为迭代器。
set<IP, IPComp> setIP;
setIP.insert(IP(1,1,1,1));
setIP.insert(IP(2,2,2,2));
setIP.insert(IP(3,3,3,3));
setIP.insert(IP(4,4,4,4));
pair<set<IP, IPComp>::iterator, bool> insert_Res;
insert_Res = setIP.insert(IP(4,4,4,4));
if(!insert_Res.second){
cout<< "InsertFailed."<< endl;
}
IP ipArr[] = {IP(100,100,100,100), IP(101,101,101,101), IP(102,102,102,102)};
setIP.insert(ipArr,ipArr+3);
1.3 元素遍历
正向遍历(以key的升序遍历,对应树的中序遍历)
for(set<IP, IPComp>::iterator itr = setIP.begin(); itr !=setIP.end(); itr++){
cout<< itr->d1;
}
1.4 元素删除
与插入一样,可以高效的删除,并自动调整使红黑树平衡。
set<int> s;
s.erase(2); //删除键值为2的元素
s.clear();
s.erase(itrFound);//itrFound为set的iterator,删除迭代器所指元素,无返回值
1.5 元素检索
find(),若找到,返回该键值迭代器的位置,否则,返回最后一个元素后面一个位置。
set<int> s;
set<int>::iterator it =s.find(5); //查找键值为5的元素
if(it!=s.end()) //找到
cout<<*it<<endl;
else //未找到
cout<<"未找到";
1.6 状态获取
set<int> s;
s.empty();//判断是否为空
s.size(); //获取元素个数
1.7 集合交并差
#include <algorithm>后就可以使用STL提供的集合运算函数。
求A,B交集:set_intersection
求A,B并集:set_union
求A,B差集:set_difference
求A,B对称差:set_symmetric_difference
以上四个函数参数完全一样。以set_intersection为例,讲解这几个函数的参数。
元素类型本身就带<操作符
template<class _InIt1,class _InIt2,class _OutIt>
_OutIt set_intersection(
_InIt1 _First1,_InIt1 _Last1,
_InIt2 _First2, _InIt2 _Last2,
_OutIt _Dest
)
元素类型本身不带<操作符,通过函数对象来实现比较的
template<class _InIt1,class _InIt2,class _OutIt, class_Pred>
_OutIt set_intersection(
_InIt1 _First1,_InIt1 _Last1,
_InIt2 _First2, _InIt2 _Last2,
_OutIt _Dest
_Pred _pre
)
set<IP> setIP;
setIP.insert(IP(1,1,1,1));
setIP.insert(IP(2,2,2,2));
setIP.insert(IP(3,3,3,3));
setIP.insert(IP(4,4,4,4));
set<IP> setIP2;
setIP2.insert(IP(1,1,1,1));
setIP2.insert(IP(2,2,2,2));
setIP2.insert(IP(91,91,91,91));
setIP2.insert(IP(92,92,92,92));
IP arr[10];
cout<< "setIP:" << endl;
for(set<IP,IPComp>::iterator itr=setIP.begin();itr!=setIP.end();itr++){
cout<<itr->d1<<"."<<itr->d2<<"."<<itr->d3<<"."<<itr->d4<<endl;
}
cout<< "setIP2:" << endl;
for(set<IP,IPComp>::iterator itr=setIP2.begin();itr!=setIP2.end();itr++){
cout<<itr->d1<<"."<<itr->d2<<"."<<itr->d3<<"."<<itr->d4<<endl;
}
IP* endArr =set_intersection(setIP.begin(), setIP.end(), setIP2.begin(), setIP2.end(),arr);
int sizeArr = endArr -arr;
cout<< "set_intersection(setIP,setIP2):"<< endl;
for(int i = 0; i <sizeArr; i ++) {
cout<<arr[i].d1<<"."<<arr[i].d2<<"."<<arr[i].d3<<"."<<arr[i].d4<<endl;
}
endArr= set_union(setIP.begin(), setIP.end(), setIP2.begin(), setIP2.end(), arr);
sizeArr= endArr - arr;
cout<< "set_union(setIP,setIP2):"<< endl;
for(int i = 0; i <sizeArr; i ++) {
cout<<arr[i].d1<<"."<<arr[i].d2<<"."<<arr[i].d3<<"."<<arr[i].d4<<endl;
}
endArr=set_difference(setIP.begin(),setIP.end(),setIP2.begin(), setIP2.end(), arr);
sizeArr= endArr - arr;
cout<< "set_difference(setIP,setIP2):"<< endl;
for(int i = 0; i < sizeArr;i ++) {
cout<<arr[i].d1<<"."<<arr[i].d2<<"."<<arr[i].d3<<"."<<arr[i].d4<<endl;
}
endArr= set_symmetric_difference(setIP.begin(), setIP.end(), setIP2.begin(),setIP2.end(), arr);
sizeArr= endArr - arr;
cout<< "set_symmetric_difference(setIP,setIP2):"<< endl;
for(int i = 0; i <sizeArr; i ++) {
cout<<arr[i].d1<<"."<<arr[i].d2<<"."<<arr[i].d3<<"."<<arr[i].d4<<endl;
}
输出结果为:
setIP:
1.1.1.1
2.2.2.2
3.3.3.3
4.4.4.4
setIP2:
1.1.1.1
2.2.2.2
91.91.91.91
92.92.92.92
set_intersection(setIP,setIP2):
1.1.1.1
2.2.2.2
set_union(setIP,setIP2):
1.1.1.1
2.2.2.2
3.3.3.3
4.4.4.4
91.91.91.91
92.92.92.92
set_difference(setIP,setIP2):
3.3.3.3
4.4.4.4
set_symmetric_difference(setIP,setIP2):
3.3.3.3
4.4.4.4
91.91.91.91
92.92.92.92
如果需要通过函数对象来提供IP的<运算符,如函数对象的类为IPComp,则需要在各函数最末尾增加一个参数,传递IPComp的对象。如集合交函数应为
set_intersection(setIP.begin(),setIP.end(), setIP2.begin(), setIP2.end(),
arr,IPComp());
1.8 multiset与set的差异
multiset和set的方法使用基本相同,只有少数区别:
multiset的允许一个集合中,出现多个相同的元素,而set中的元素具有唯一性,相同是在操作符==比较的意义上。
- count
set:有元素匹配,返回1;否则,返回0。
multiset:返回multiset 中其键与指定为参数的键匹配的元素数量。
- setA.erase(element);
set:删除集合中的唯一的值为element的元素;
multiset:删除集合中的所有值为element的元素。
- setA.erase(iteratorA);
都只是删除iteratorA指向的单个元素
- find
set:返回唯一匹配元素的位置
multiset:返回第一个匹配元素的位置