码迷,mamicode.com
首页 > 其他好文 > 详细

set集合容器

时间:2016-05-27 23:23:16      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:

近期学习了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 }

元素的插入与中序遍历:

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

 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()来清空集合。

明天更,哈哈

set集合容器

标签:

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!