C++标准程序库之set,multiset

set和multiset会根据特定的排序准则,自动将元素排序。两者的不同之处在于multiset允许元素重复而set不允许。

使用set或multiset之前,必须包含头文件<set>,在该头文件中,上述两个类型都被定义为命名空间std内的class template:

只要是assignable、copyable、comparable(根据某个排序准则)的类型T,都可以成为set或multiset的元素类型。
可有可无的第二个参数用来定义排序准则,如果没有传入特别的排序准则,就采用缺省准则less——这是个仿函数,以operator<对元素进行比较,以便完成排序。
可有可无的第三个参数用来定义内存模型。缺省的内存模型是allocator,有C++标准程序库提供。

1.set和multiset的能力

(1)和所有标准关联式容器类似,set和multiset通常以平衡二叉树完成。
(2)自动排序的主要优点在于使二叉树于搜寻元素时具有良好性能。其搜寻函数算法具有对数复杂度。
(3)但是,自动排序造成set和multiset的一个重要限制:你不能直接改变元素值,因为这样会打乱原本正确的顺序。因此,要改变元素值,必须先删除旧元素,再插入新元素。这里提供的接口正反映了这种行为:

  • set和multiset不提供用来直接存取元素的任何操作函数。
  • 通过迭代器进行元素间接存取,有一个限制:从迭代器的角度来看,元素值是常数。
2.set和multiset的操作函数

(1)set和multiset的构造函数和析构函数

(2)set和multiset的非变动性操作

(3)set和multiset的搜寻操作函数

考虑如下示例:

输出:

(4)set和multiset的赋值操作

(5)set和multiset的迭代器相关操作函数

(6)set和multiset的元素插入和移除

注意,插入函数的返回类型不尽相同:

  • set提供如下接口:
  • multiset提供如下接口:

    返回类型不同的原因是:multiset允许元素重复,而set不允许。因此如果将某元素插入set内,而该set已经内含同值元素,则插入操作将失败。所以set的返回类型是以pair组织起来的两个值:
    1)pair结构中的second成员表示插入是否成功。
    2)pair结构中的first成员返回新元素的位置,或返回现存的同值元素的位置。

注意,作用于序列式容器和关联式容器erase()函数,其返回值有一下不同:
1)序列式容器earse()成员函数:
iterator erase(iterator pos);
iterator erase(iterator beg, iterator end);

2)关联式容器erase()成员函数:
void erase(iterator pos);
void erase(iterator beg, iterator end);

存在这种差别,完全是为了性能。在关联式容器中“搜寻某元素并返回后继元素”可能颇为耗时,因为这种容器的底部是以二叉树完成,所以如果你想编写对所有容器都适用的程序,你必须忽略返回值。

3.异常处理

set和multiset是“以节点(nodes)为基础”的容器。如果节点构造失败,容器仍保持原样。此外,由于析构函数通常不抛出异常,所以节点的移除不可能失败。

然后,面对多重元素插入操作,“保持元素次序”这一条件会造成“异常抛出时能够完全复原”这一需求变得不切实际。因此只有“单一元素插入操作”才支持“成功 ,否则无效”的操作原则。至于“多元素删除操作”总是能够成功。如果排序准则之复制/赋值操作会抛出异常,则swap()也会抛出异常。

4.set和multiset运用实例

(1)set.cpp

输出:

(2)multiset.cpp

编译输出:

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注