set集合容器

近期学习了STL中set的使用,在此写一点点总结和自己的一些体悟。

     set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与有字数的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。

     平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。

     那么现在有人就要问了,为何set的插入、删除、检索效率要比其他序列容器高?

首先我们要了解set的储存方式,set内部采用的是红黑树(也称为RB树),红黑树是一种非常高效的平衡检索二叉树。基于红黑树,set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。结构图可能如下:

      A
   /
  B C
 / /
  D E F G

因此插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍做变换后把指向删除节点的指针指向其他节点也OK了。这里的一切操作就是指针换来换去,和内存移动没有关系。

那么当数据元素增多时,set的插入、删除和搜索速度变化如何呢?

如果你知道log2的关系你应该就彻底了解这个答案。在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。

使用set前,需要在程序头文件中包含声明“#include<set>”。

下面我们列出一些set中的常用操作:(英语好的小伙伴可以进这个链接看看,包含了set的几乎所有操作

首先是创建set集合对象:

1 #include<set>
2 
3 using namespace std;
4 
5 int main(){
6     set<int> s;//定义元素类型为int的集合对象,当前没有任何元素 
7     return 0;
8 }

元素的插入与中序遍历:

采用insert()方法把元素插入到集合中,插入规则在默认的比较规则下,是按元素值从小到大插入,如果自己指定了比较规则函数,则按自定义比较规则函数插入。使用前向迭代器对集合中序遍历,结果正好是元素排序后的结果。

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

运行结果:

1 6 8 12

我们也可以使用反向迭代器reverse_iterator来反向遍历集合,输出结果正好是集合元素的反向排序结果。它需要用到rbegin()和rend()两个方法,他们分别给出了反向遍历的开始位置和结束位置。

 1 #include<iostream>
 2 #include<set>
 3 using namespace std;
 4 
 5 int main(){
 6     set<int> s;
 7     s.insert(8);//插入了五个元素,但由于第二次插入8有重复,所以第二次插入8并没有执行 
 8     s.insert(1);
 9     s.insert(12);
10     s.insert(6);
11     s.insert(8);
12     
13     set<int>::reverse_iterator it;//定义反向迭代器 
14     for(it=s.rbegin();it!=rend();it++){//反向遍历 
15         cout<<*it<<" ";
16     }
17     cout<<endl;
18     return 0;
19 }

运行结果

12 8 6 1

元素的删除:

元素可以使用erase()来删除某键值的元素,也可以使用clear()来清空集合。

 1 #include<iostream>
 2 #include<set>
 3 using namespace std;
 4 
 5 int main(){
 6     set<int> s;
 7     s.insert(8);//插入了五个元素,但由于第二次插入8有重复,所以第二次插入8并没有执行 
 8     s.insert(1);
 9     s.insert(12);
10     s.insert(6);
11     s.insert(8);
12     
13     s.erase(6);//删除键值为6的那个元素
14     set<int>::iterator it;
15     for(it=s.begin();it!=s.end();it++){
16         cout<<*it<<" ";
17     } 
18     cout<<endl;
19     s.clear();//清空集合
20     cout<<s.size()<<endl;//输出集合大小
21     return 0; 
22 }

运行结果:

12 8 1

0

元素的检索:

我们可以使用find()来对集合进行搜索,如果找到查找的键值,则返回键值的迭代器位置,否则,返回集合最后一个元素后面的一个位置,即end()。

 1 #include<iostream>
 2 #include<set>
 3 using namespace std;
 4 
 5 int main(){
 6     set<int> s;
 7     s.insert(8);
 8     s.insert(1);
 9     s.insert(12);
10     s.insert(6);
11     s.insert(8);
12     
13     set<int>::iterator it;
14     it=s.find(6);//查找键值为6的元素 
15     if(it!=s.end()){//找到 
16         cout<<*it<<endl;
17     }
18     else//没找到 
19     cout<<"not find it"<<endl;
20     it=find(20);//查找键值为20的元素 
21     if(it!=s.end())
22     cout<<*it<<endl;
23     else
24     cout<<"not find it"<<endl;
25     return 0;
26 }

其他操作:

其中一些我们程序中也用到过。

c++ stl容器set成员函数:begin()--返回指向第一个元素的迭代器

c++ stl容器set成员函数:clear()--清除所有元素

c++ stl容器set成员函数:count()--返回某个值元素的个数

c++ stl容器set成员函数:empty()--如果集合为空,返回true

c++ stl容器set成员函数:end()--返回指向最后一个元素的迭代器

c++ stl容器set成员函数:equal_range()--返回集合中与给定值相等的上下限的两个迭代器

c++ stl容器set成员函数:erase()--删除集合中的元素

c++ stl容器set成员函数:find()--返回一个指向被查找到元素的迭代器

c++ stl容器set成员函数:get_allocator()--返回集合的分配器

c++ stl容器set成员函数:insert()--在集合中插入元素

c++ stl容器set成员函数:lower_bound()--返回指向大于(或等于)某值的第一个元素的迭代器

c++ stl容器set成员函数:key_comp()--返回一个用于元素间值比较的函数

c++ stl容器set成员函数:max_size()--返回集合能容纳的元素的最大限值

c++ stl容器set成员函数:rbegin()--返回指向集合中最后一个元素的反向迭代器

c++ stl容器set成员函数:rend()--返回指向集合中第一个元素的反向迭代器

c++ stl容器set成员函数:size()--集合中元素的数目

c++ stl容器set成员函数:swap()--交换两个集合变量

c++ stl容器set成员函数:upper_bound()--返回大于某个值元素的迭代器

c++ stl容器set成员函数:value_comp()--返回一个用于比较元素间的值的函数

原文地址:https://www.cnblogs.com/Kiven5197/p/5536370.html