近期学习了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()来清空集合。
明天更,哈哈