zoukankan      html  css  js  c++  java
  • STL标准库-容器-set与multiset

    技术在于交流、沟通,转载请注明出处并保持作品的完整性。

    set与multiset关联容器

    结构如下

    set是一种关联容器,key即value,value即key.它是自动排序,排序特点依据key

    set的key不能相同.multiset的key相同.关联容器的查找效率要高于顺序容器很多很多.

    set和multiset不提供用来直接存取元素的任何操作函数,取值需要通过迭代器


    一 定义

    1.set/mulitiset以红黑树为底层结构,因此有元素自动排序的特性,排序是根据key,而set.multiset的元素的value和key相同

    2.set/multiset提供遍历即迭代器操作,获得排序后的状态

    3.我们无法使用迭代器改变set/multiset改变元素值,实现原理是RB tree 的const iterator

    4.set元素的key必须对无二,因此其insert()用的rb_tree的insert_unique()

    5.multiset的元素key可以重复,因此其insert()用的是rb_tree的insert_equal()

     set的源码

    template <class _Key, class _Compare = less<_Key>,
              class _Allocator = allocator<_Key> >
    class _LIBCPP_TYPE_VIS_ONLY set
    {
        ...
    private:
        typedef __tree<value_type, value_compare, allocator_type> __base;
        ...
        __base __tree_;
        ...
    }

    第一参数 key 是key的类型 ,

    第二参数 compare 比较函数,key的排序函数

    第三参数 默认的分配器

    使用介绍

    //1.定义
        set<int> c;
        
        for(auto i : c)
        {
            cout << i << endl;
        }
        cout << "ctor" <<endl;
        
        //2.initializer ctor
        set<int> c1 = {1,2,3,7,6,4,5};//set当插入相同元素时,会插入不成功,但是不会有任何提示
        
        for(auto i : c1)
        {
            cout << i << endl;
        }
        cout << "initializer_ctor" <<endl;//会发现set有自动排序的功能,因为他的底层实现使红黑树
        
        //3.数组转换
        int arrayOfSet[] = {10,20,30,40,50};
        
        std::set<int> c2(arrayOfSet,arrayOfSet+5);
        
        for(auto i : c2)
        {
            cout << i << endl;
        }
        cout << "initializer_ctor" <<endl;
        
        //4.operator =
        c = c1;
        
        for(auto i : c)
        {
            cout << i << endl;
        }
        cout << "operator= " <<endl;

    二 set迭代器

    //迭代器操作 正向迭代器
        set<int>::iterator iteBegin = c.begin();
        set<int>::iterator iteEnd = c.end();
        
        cout<< "*iteBegin: "<< *iteBegin << endl;
        iteEnd--;
        cout<< "*iteEnd: "<< *iteEnd << endl;
    
        //正向const迭代器,不能改变,其实不需要知道正向迭代器和反向,反正都不能使用迭代器直接修改其元素
        set<int>::const_iterator iteCBegin = c.cbegin();
        set<int>::const_iterator iteCEnd = c.cend();
        
        cout<< "*iteCBegin: "<< *iteCBegin << endl;
        iteCEnd--;
        cout<< "*iteCEnd: "<< *iteCEnd << endl;
        
        
        //反向迭代器
        set<int>::reverse_iterator iteRBegin = c.rbegin();
        set<int>::reverse_iterator iteREnd = c.rend();
        
        cout<< "*iteRBegin: "<< *iteRBegin << endl;
        iteREnd--;
        cout<< "*iteCEnd: "<< *iteREnd << endl;
        
        //反向cosnt迭代器
        set<int>::const_reverse_iterator iteCRBegin = c.crbegin();
        set<int>::const_reverse_iterator iteCREnd = c.crend();
        
        cout<< "*iteCRBegin: "<< *iteCRBegin << endl;
        iteCREnd--;
        cout<< "*iteCEnd: "<< *iteCREnd << endl;

    三 容量

        //容量
        //判断是否为null
        cout << "empty: " << c.empty() <<endl;
        
        //大小size
        cout << "size: " << c.size() <<endl;
        
        //最大容量max_size
        cout << "max_size: " << c.max_size() <<endl;

    四 基本操作

    //操作
        //插入
        c.insert(10);
        for(auto i : c)
        {
            cout << i << endl;
        }
        cout << "insert" <<endl;
        
        //指定元素删除
        c.erase(10);
        for(auto i : c)
        {
            cout << i << endl;
        }
        cout << "erase" <<endl;
        
        
        //指定位置删除
        advance(iteBegin, 3);
        c.erase(iteBegin);
        for(auto i : c)
        {
            cout << i << endl;
        }
        cout << "erase" <<endl;
        
        
        //交换
        c.swap(c2);
        for(auto i : c)
        {
            cout << i << endl;
        }
        cout << "swap" <<endl;
        
        //清除
        set<int> c3 = c2;
        c3.clear();
        for(auto i : c3)
        {
            cout << i << endl;
        }
        cout << "clear" <<endl;
        
        //判断是否存在1 ,存在返回false, 不存在返回1
        for(auto i : c)
        {
            cout << i << endl;
        }
        auto ret = c.emplace(1);
        if (!ret.second) cout << "1 already exists in myset
    ";
        else  cout << "1 non-exists in myset
    ";
        
    
        //如果不存在元素1 则插入1,如果存在则什么也不做
        c.emplace(1);
        for(auto i : c)
        {
            cout << i << endl;
        }
    
        //key_comp返回存储的函数对象
        //set 的默认比较key函数是 less()函数,且set中value和key是同一元素,即从小到大排序
        
        cout << c.key_comp()(1,2) <<endl; //会返回1  因为1<2
        cout << c.key_comp()(2,1) <<endl; //会返回0  因为2>1
        cout << c.key_comp()(1,1) <<endl; //会返回0  因为1=1
        
        //key_comp返回比较key的函数对象,即返回比较函数相同功能的函数
        cout << c.value_comp()(1,2) <<endl; //会返回1  因为1<2
        cout << c.value_comp()(2,1) <<endl; //会返回0  因为2>1
        cout << c.value_comp()(1,1) <<endl; //会返回0  因为1=1

    五 基本算法

    //算法类
        //find 查看是否含有该元素 如果有返回指向该点的迭代器 如果没有返回 end()
        auto findObj = c.find(40);
        if(*findObj)
         cout<<*findObj<<endl;
        else
            cout<< "not found" << endl;
        
        //元素出现个数
        cout << "count: " << c.count(1) <<endl;
        
        //lower_bound(key_value) ,返回第一个大于等于key_value的迭代器
        
        auto lower_boundObj = c.lower_bound(25);
        if(*lower_boundObj)
         cout<<*lower_boundObj<<endl;
        else
            cout<< "lower_boundObj" << endl;
        
        //upper_bound(key_value),返回最后一个大于等于key_value的迭代器
        auto upper_boundObj = c.upper_bound(25);
        if(*upper_boundObj)
         cout<<*upper_boundObj<<endl;
        else
            cout<< "upper_boundObj" << endl;
        
    
        //equal_range()返回该元素所在区间(闭区间),返回值是一个pair类型,first代表所在区间的起点,second表示所在区间的重点
        //如set<int> c {1,2,3,4,5}
        //c.equal_range(3) ,first就是指向3的迭代器  second就是指向4的迭代器
        
        auto equal_rangeObj = c.equal_range(30);
        if(*equal_rangeObj.first)
         cout<<*equal_rangeObj.first<<endl;
        else
            cout<< "NOT equal_rangeObj.first" << endl;
        
        if(*equal_rangeObj.second)
         cout<<*equal_rangeObj.second<<endl;
        else
            cout<< "NOT equal_rangeObj.second" << endl;

    六 自定义比较函数

        //自定义比较函数
        //set的默认比较key函数是less 下面我演示一下用自定义比较函数
    //    class my_comp
    //    {
    //    public:
    //        bool operator()(int a, int b)
    //        {
    //            return a > b;
    //        }
    //    };
        set<int, my_comp> my_set = {5,2,3,4,1};
        for(auto i : my_set)
        {
            cout << i << endl;
        }

    source code

    类图

    set的底层结构是rb_tree(),应该说set是一个容器适配器.它封装了rb_tree的方法,先介绍一下set的参数含义

        template<typename _Key, typename _Compare = std::less<_Key>,
        typename _Alloc = std::allocator<_Key> >
        class set
        {
            public:
                // typedefs:
                //@{
                /// Public typedefs.
                typedef _Key     key_type;          // Key value
                typedef _Key     value_type;        //(key+value的数据包)
                typedef _Compare key_compare;       // key的比较函数
                typedef _Compare value_compare;     // 
                typedef _Alloc   allocator_type;    // 分配器
                //@}
                
            private:
                typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
                rebind<_Key>::other _Key_alloc_type;
                
                typedef _Rb_tree<key_type, value_type, _Identity<value_type>,
                key_compare, _Key_alloc_type> _Rep_type;
                _Rep_type _M_t;  // Red-black tree representing set.
    
            ...
            
            set()
            : _M_t() { }
            
            ...
            
            std::pair<iterator, bool>
            insert(const value_type& __x)
            {
                std::pair<typename _Rep_type::iterator, bool> __p =
                              _M_t._M_insert_unique(__x);
                return std::pair<iterator, bool>(__p.first, __p.second);
            }
            
            ...
        }

     更详细实现我会在rb_tree介绍

     参考<<侯捷STL标准库>>

  • 相关阅读:
    Android Studio无法预览xml布局之解决方法(两种)
    ssm web.xml配置解析
    ssm框架下实现文件上传
    spring mvc使用@InitBinder 标签对表单数据绑定
    Jquery实现相对浏览器位置固定、悬浮
    asp,php,jsp 不缓存网页的办法
    Spring 2.5
    ERROR 1366 (HY000): Incorrect string value: 'xB3xA4xC9xB3' for column
    DELPHI SOKET 编程--使用TServerSocket和TClientSocket
    SVN switch 用法总结
  • 原文地址:https://www.cnblogs.com/LearningTheLoad/p/7456024.html
Copyright © 2011-2022 走看看