zoukankan      html  css  js  c++  java
  • 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()--返回一个用于比较元素间的值的函数

  • 相关阅读:
    javascript之createElement事件
    rgb颜色列表
    欧美很好听的调调
    转:JMeter--使用代理录制Web性.能测试脚.本
    转:使用 JMeter 完成常用的压力测试
    转: 理解 JMeter 聚合报告(Aggregate Report)
    转:jmeter实践
    转:支付漏洞的三种常见类型
    转:LoadRunner获取毫秒及字符串替换实现
    转:Windows平台配置Appium+Java环境
  • 原文地址:https://www.cnblogs.com/Kiven5197/p/5536370.html
Copyright © 2011-2022 走看看