STL与泛型编程<五>:Sets和Multisets

set和multiset会根据特定的排序准则排序,自动将元素进行排序,不同之处在于multiset允许元素重复而set不允许。
这里写图片描述
其声明如下

namespace std
{
    template<class T, class Compare = less<T>, class Allocator = allocator<T> > 
    class set;

    template<class T, class Compare = less<T>, class Allocator = allocator<T> > 
    class multiset;
}
/*
这里的T就是set::key_type/value_type;
这里的 Compare就是set::key_cmpare/value_cmpare;
对于set,key就是value,value就是key
*/ 

如果没有传入特别的排序准则,就采用缺省的准则less-这是一个仿函数,以operator < 对元素进行比较。

sets和multisets的能力

sets和multisets通常以平衡二叉树(红黑树)完成(见下图),自动排序的主要优点在于其搜寻算法具有对数复杂度。但是也造成个限制你不能直接改变元素值,因为这会打乱原本正确的顺序。因此要改变元素值,必须先删除就元素,再插入新元素
这里写图片描述

sets和multisets的操作函数

  • 生成 复制 销毁
    这里写图片描述

非变动性操作

元素的比较动作只能比较型别相同(元素和排序准则都必须相同)的元素
这里写图片描述

特殊的搜寻函数

equal_range则是将lower_bound()和upper_bound()的返回值做成一个pair返回,所以它返回的是“与参数值相等”的元素所形成的区间,如果lower_bound()或“equal_range()的第一值”等于“equal_range()的第二值”或upper_bound(),则此set或multiset内部存在相同的数值。见下面例子

#include <set>
#include <algorithm>
#include <iostream>

using namespace std;

int main(void)
{
    set<int> col;
    col.insert(1);
    col.insert(2);
    col.insert(4);
    col.insert(5);
    col.insert(6);

    cout << "lower_bound(3): " << *col.lower_bound(3) << endl; // 4
    cout << "upper_bound(3): " << *col.upper_bound(3) << endl; // 4
    cout << "equal_range(3): " << *col.equal_range(3).first << " "<< *col.equal_range(3).second << endl;// 4 4

    cout << endl;
    cout << "lower_bound(5): " << *col.lower_bound(5) << endl;//5
    cout << "upper_bound(5): " << *col.upper_bound(5) << endl;//6
    cout << "equal_range(5): " << *col.equal_range(5).first << " "
                               << *col.equal_range(5).second << endl;//5 6

    return 0;
 } 

赋值

这些操作函数,赋值操作的两端容器必须具有同的型别
这里写图片描述

迭代器相关函数

注意这里的迭代器是双向迭代器,对于只能用于随机迭代器的STL算法来说,就不能使用了,也不能对其调用任何变动性算法,如remove。
这里写图片描述

元素的安插和移除

这里写图片描述
sets提供以下接口:

/*
pair结构中的second表示安插是否成功,first成员返回新元素的位置,或返回现存的同值元素的位置。
*/
pair<iterator,bool> insert(const value_type& elem);
iterator  insert(iterator pos_hint,const value_type& elem);

因此可以如下使用

set<double> c;
if (c.insert(3.3).second)
{
    cout << "3.3 inserted " << endl;
}
else
{
    cout << 
  
  
   
   "3.3 already exits " << endl;
}
  
  

multisets提供以下接口

iterator  insert(const value_type& elem);
iterator insert(iterator pos_hint,const value_type& elem);

返回值型别的不同是因为set不允许重复,而multisets允许重复,因此如果将某元素安插至一个set内,而该set已经内含同值元素,则安插失败。

一个示例

#include <set>
#include <algorithm>
#include <iostream>
#include <iterator>

using namespace std;

int main(void)
{
    typedef set<int,greater<int> > IntSet;
    IntSet col1;
    col1.insert(4);
    col1.insert(3);
    col1.insert(5);
    col1.insert(1);
    col1.insert(6);
    col1.insert(2);
    col1.insert(5);

    IntSet::iterator pos;
    for (pos=col1.begin(); pos!=col1.end(); ++pos)
    {
        cout << *pos << endl;  //6 5 4 3 2 1
    }
    cout << endl;   

    //插入4 
    pair<IntSet::iterator,bool> status = col1.insert(4);
    if (status.second)
    {
        cout << "4 inserted as element"
            << distance(col1.begin(),status.first) + 1
            << endl;
    }
    else
    {
        cout << "4 already exits" << endl; //打印 
    }

    set<int> col2(col1.begin(),col1.end());
    copy(col2.begin(),col2.end(),ostream_iterator<int>(cout," "));  // 1 2 3 4 5 6
    cout << endl;

    //移除3 
    col2.erase(col2.begin(),col2.find(3));  // 3 4 5 6注意3没被移除,一般区间处理都是左闭右开

    int num;
    num = col2.erase(5);
    cout << num << " element(s) removed" << endl; //3 4 6 

    copy(col2.begin(),col2.end(),ostream_iterator<int>(cout," ")); //3 4 6
    cout << endl;
    return 0;
} 

对于multisets,上诉程序如下

#include <set>
#include <algorithm>
#include <iostream>
#include <iterator>

using namespace std;

int main(void)
{
    typedef multiset<int,greater<int> > IntSet;
    IntSet col1;
    col1.insert(4);
    col1.insert(3);
    col1.insert(5);
    col1.insert(1);
    col1.insert(6);
    col1.insert(2);
    col1.insert(5);

    IntSet::iterator pos;
    for (pos=col1.begin(); pos!=col1.end(); ++pos)
    {
        cout << *pos << endl;  //6 5 5 4 3 2 1
    }
    cout << endl;   

    //插入4 
    IntSet::iterator ipos = col1.insert(4);  //insert返回新元素的位置 
    cout << "4 inserted as element"
        << distance(col1.begin(),ipos) + 1 << endl;  //5


    multiset<int> col2(col1.begin(),col1.end());
    copy(col2.begin(),col2.end(),ostream_iterator<int>(cout," "));  // 1 2 3 4 4 5 5 6
    cout << endl;

    //移除3 
    col2.erase(col2.begin(),col2.find(3));  // 3 4 4 5 5 6

    int num;
    num = col2.erase(5);
    cout << num << " element(s) removed" << endl; //2

    copy(col2.begin(),col2.end(),ostream_iterator<int>(cout," ")); //3 4 4 6
    cout << endl;
    return 0;

} 

在此处输入标题

补充

有两种方式定义排序准则
1. 以template参数定义之(就是将排序准则当作是容器的类型,当然更推荐这种)
2. 以构造函数参数定义
至于2见以下程序

#include <iostream>
#include <set>
#include <algorithm>
#include <iterator> 
using namespace std;

template<typename T>
class RuntimeCmp
{
    public:
        enum cmp_mode {normal, reverse};
    private:
        cmp_mode mode;
    public:
        RuntimeCmp(cmp_mode m=normal) : mode(m) {}

        bool operator() (const T& t1, const T& t2)//必须得提供此函数
        {
            return mode == normal ? t1 < t2 : t2 < t1;
        }

        bool operator == (const RuntimeCmp& rc)
        {
            return mode == rc.mode;
        }
};

typedef set<int, RuntimeCmp<int> > IntSet;
void fill(IntSet& col);

int main(void)
{
    IntSet col;
    fill(col);
    copy(col.begin(),col.end(),ostream_iterator<int>(cout," "));
    cout << endl;

    RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse); 
    IntSet col2(reverse_order);
    fill(col2);
    copy(col2.begin(),col2.end(),ostream_iterator<int>(cout," "));
    cout << endl;

    col = col2;  //排序准则也赋值了 
    col.insert(3);
    copy(col.begin(),col.end(),ostream_iterator<int>(cout," "));
    cout << endl;

    if (col.value_comp() == col2.value_comp())
        cout << "col and col2 have the same sort" << endl;

    return 0;
}

void fill(IntSet& col)
{
    col.insert(4);
    col.insert(7);
    col.insert(5);
    col.insert(1);
    col.insert(6);
    col.insert(2);
    col.insert(5);
}
/*
算是自定义排序准则,一定得在自定义型别中重载operator()操作符,且在词函数中定义排序准则。
*/ 

此外set容器还提供了两个函数

key_compare key_comp() const;
value_compare value_comp() const;

下面见一个例子

#include <iostream>
#include <set>

int main (void)
{
  std::set<int> myset;
  int highest;

  std::set<int>::key_compare mycomp = myset.key_comp();  //默认为less仿函数 

  for (int i=0; i<=5; i++) 
        myset.insert(i);

  std::cout << "myset contains:";

  highest=*myset.rbegin(); //最后一个元素,按照less的排序准则,应该是最大的 
  std::cout << highest << std::endl;  //果然是5 
  std::set<int>::iterator it=myset.begin();
  do {
    std::cout << ' ' << *it;
  } while ( mycomp(*(++it),highest) );

  std::cout << '\n';

  return 0;
}
/*less原型: 
template <class T> 
struct less : binary_function <T,T,bool> 
{
  bool operator() (const T& x, const T& y) const {return x<y;}
};
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值