C++中 set(集合容器)的用法

set集合容器:

  实现了红黑树(Red-Black Tree)的平衡二叉检索树的数据结构,在插入元素时,

它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,

而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与有字数的高度相等,

这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。

  平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。

另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,

就会自动将元素按键值从小到大的顺序排列。

     构造set集合的主要目的是为了快速检索,使用set前,需要在程序头文件中包含声明“#include<set>”。

 

c++ stl集合(Set):

  是一种包含已排序对象的关联容器。set/multiset会根据待定的排序准则,

  自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。

  1) 不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素

  2) 不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数

  3) 元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同)

 

set的各成员函数列表如下:

begin()--返回指向第一个元素的迭代器

 clear()--清除所有元素

 count()--返回某个值元素的个数

 empty()--如果集合为空,返回true

 end()--返回指向最后一个元素的迭代器

 equal_range()--返回集合中与给定值相等的上下限的两个迭代器

 erase()--删除集合中的元素

 find()--返回一个指向被查找到元素的迭代器

 get_allocator()--返回集合的分配器

 insert()--在集合中插入元素

 lower_bound()--返回指向大于(或等于)某值的第一个元素的迭代器

 key_comp()--返回一个用于元素间值比较的函数

 max_size()--返回集合能容纳的元素的最大限值

 rbegin()--返回指向集合中最后一个元素的反向迭代器

 rend()--返回指向集合中第一个元素的反向迭代器

 size()--集合中元素的数目

 swap()--交换两个集合变量

 upper_bound()--返回大于某个值元素的迭代器

 value_comp()--返回一个用于比较元素间的值的函数

 

1.创建set集合对象

           创建set对象时,需要指定元素的类型,这一点和其他容器一样。

1 #include<iostream>  
2 #include<set>  
3 using namespace std;  
4 int main()  
5 {  
6     set<int> s;  
7     return 0;  
8 } 

2.元素的插入与中序遍历

        采用inset()方法把元素插入到集合中,插入规则在默认的比较规则下,

是按元素值从小到大插入,如果自己指定了比较规则函数,则按自定义比较规则函数插入。

使用前向迭代器对集合中序遍历,结果正好是元素排序后的结果。

 1 #include<iostream>  
 2 #include<set>  
 3 using namespace std;  
 4 int main()  
 5 {  
 6     set<int> s;  
 7     s.insert(5); //第一次插入5,可以插入  
 8     s.insert(1);  
 9     s.insert(6);  
10     s.insert(3);  
11     s.insert(5); //第二次插入5,重复元素,不会插入  
12     set<int>::iterator it; //定义前向迭代器  
13     //中序遍历集合中的所有元素  
14     for(it = s.begin(); it != s.end(); it++)  
15     {  
16         cout << *it << " ";  
17     }  
18     cout << endl;  
19     return 0;  
20 }  
21 //运行结果:1 3 5 6 

3.元素的方向遍历

        使用反向迭代器reverse_iterator可以反向遍历集合,输出的结果正好是集合元素的反向排序结果。

    它需要用到rbegin()和rend()两个方法,它们分别给出了反向遍历的开始位置和结束位置。

 1 #include<iostream>  
 2 #include<set>  
 3 using namespace std;  
 4 int main()  
 5 {  
 6     set<int> s;  
 7     s.insert(5); //第一次插入5,可以插入  
 8     s.insert(1);  
 9     s.insert(6);  
10     s.insert(3);  
11     s.insert(5); //第二次插入5,重复元素,不会插入  
12     set<int>::reverse_iterator rit; //定义反向迭代器  
13     //反向遍历集合中的所有元素  
14     for(rit = s.rbegin(); rit != s.rend(); rit++)  
15     {  
16         cout << *rit << " ";  
17     }  
18     cout << endl;  
19     return 0;  
20 }  
21 //运行结果:6 5 3 1 

4.元素的删除

        与插入元素的处理一样,集合具有高效的删除处理功能,并自动重新调整内部的红黑树的平衡。

    删除的对象可以是某个迭代器位置上的元素、等于某键值的元素、一个区间上的元素和清空集合。

 1 #include<iostream>  
 2 #include<set>  
 3 using namespace std;  
 4 int main()  
 5 {  
 6     set<int> s;  
 7     s.insert(5); //第一次插入5,可以插入  
 8     s.insert(1);  
 9     s.insert(6);  
10     s.insert(3);  
11     s.insert(5); //第二次插入5,重复元素,不会插入  
12     s.erase(6); //删除键值为6的元素  
13     set<int>::reverse_iterator rit; //定义反向迭代器  
14     //反向遍历集合中的所有元素  
15     for(rit = s.rbegin(); rit != s.rend(); rit++)  
16     {  
17         cout << *rit << " ";  
18     }  
19     cout << endl;   
20     set<int>::iterator it;  
21   
22     it = s.begin();  
23     for(int i = 0; i < 2; i++)  
24         it = s.erase(it);   
25     for(it = s.begin(); it != s.end(); it++)  
26         cout << *it << " ";  
27     cout << endl;  
28   
29     s.clear();  
30     cout << s.size() << endl;  
31   
32     return 0;  
33 }  
34 /* 
35 运行结果: 
36 5 3 1 
37 5 
38 0     
39 */ 

5.元素的检索

          使用find()方法对集合进行检索,如果找到查找的的键值,则返回该键值的迭代器位置;

     否则,返回集合最后一个元素后面的一个位置,即end()。

 1 #include<iostream>  
 2 #include<set>  
 3 using namespace std;  
 4 int main()  
 5 {  
 6     set<int> s;  
 7     s.insert(5); //第一次插入5,可以插入  
 8     s.insert(1);  
 9     s.insert(6);  
10     s.insert(3);  
11     s.insert(5); //第二次插入5,重复元素,不会插入  
12     set<int>::iterator it;  
13     it = s.find(6); //查找键值为6的元素  
14     if(it != s.end())  
15         cout << *it << endl;  
16     else  
17         cout << "not find it" << endl;  
18     it = s.find(20);  
19     if(it != s.end())  
20         cout << *it << endl;  
21     else  
22         cout << "not find it" << endl;  
23     return 0;  
24 }  
25 /* 
26 运行结果: 
27 6 
28 not find it    
29 */  

下面这种方法也能判断一个数是否在集合中:

 1 #include <cstdio>  
 2 #include <set>  
 3 using namespace std;  
 4 int main() {  
 5     set <int> s;  
 6     int a;  
 7     for(int i = 0; i < 10; i++)  
 8         s.insert(i);  
 9     for(int i = 0; i < 5; i++) {  
10         scanf("%d", &a);  
11         if(!s.count(a)) //不存在  
12             printf("does not exist\n");  
13         else  
14             printf("exist\n");  
15     }  
16     return 0;  
17 }  

6.自定义比较函数

         使用insert将元素插入到集合中去的时候,集合会根据设定的比较函数奖该元素放到该放的节点上去。

在定义集合的时候,如果没有指定比较函数,那么采用默认的比较函数,即按键值从小到大的顺序插入元素。

但在很多情况下,需要自己编写比较函数。

 

编写比较函数有两种方法。

(1)如果元素不是结构体,那么可以编写比较函数。下面的程序比较规则为按键值从大到小的顺序插入到集合中。

 1 #include<iostream>  
 2 #include<set>  
 3 using namespace std;  
 4 struct mycomp  
 5 { //自定义比较函数,重载“()”操作符  
 6     bool operator() (const int &a, const int &b)  
 7     {  
 8         if(a != b)  
 9             return a > b;  
10         else  
11             return a > b;  
12     }  
13 };  
14 int main()  
15 {  
16     set<int, mycomp> s; //采用比较函数mycomp  
17     s.insert(5); //第一次插入5,可以插入  
18     s.insert(1);  
19     s.insert(6);  
20     s.insert(3);  
21     s.insert(5); //第二次插入5,重复元素,不会插入  
22     set<int,mycomp>::iterator it;  
23     for(it = s.begin(); it != s.end(); it++)  
24         cout << *it << " ";  
25     cout << endl;  
26     return 0;  
27 }  
28 /* 
29 运行结果:6 5 3 1   
30 */ 

(2)如果元素是结构体,那么可以直接把比较函数写在结构体内。

 1 #include<iostream>  
 2 #include<set>  
 3 #include<string>  
 4 using namespace std;  
 5 struct Info  
 6 {  
 7     string name;  
 8     double score;  
 9     bool operator < (const Info &a) const // 重载“<”操作符,自定义排序规则  
10     {  
11         //按score由大到小排序。如果要由小到大排序,使用“>”即可。  
12         return a.score < score;  
13     }  
14 };  
15 int main()  
16 {  
17     set<Info> s;  
18     Info info;  
19   
20     //插入三个元素  
21     info.name = "Jack";  
22     info.score = 80;  
23     s.insert(info);  
24     info.name = "Tom";  
25     info.score = 99;  
26     s.insert(info);  
27     info.name = "Steaven";  
28     info.score = 60;  
29     s.insert(info);  
30   
31     set<Info>::iterator it;  
32     for(it = s.begin(); it != s.end(); it++)  
33         cout << (*it).name << " : " << (*it).score << endl;   
34     return 0;  
35 }  
36 /* 
37 运行结果: 
38 Tom : 99 
39 Jack : 80 
40 Steaven : 60 
41 */  

 

 

posted @ 2017-05-17 14:11  gaoyanliang  阅读(21071)  评论(7编辑  收藏  举报