一、特点
set和multiset会根据特定的排序准则,自动将元素排序。两者不同之处在于multiset允许元素重复而set不允许。
二、构造和析构
set c //产生一个空的set/multiset,其中不含任何元素
set c(op) //以op为排序准则,产生一个空的set/multiset
set c1(c2) //产生某个set/multiset的副本,所有元素均被复制
set c(beg,end) //以区间[beg,end]内的元素产生一个set/multiset
set c(beg,end,op) //以op为准则,利用区间[beg,end]内的元素产生一个set/multiset
c.~set() //销毁所有元素,释放内存
其中set可为下列形式
set<Elem> //一个set,以less<>(operator<)为准则排序
set<Elem,op> //一个set,以op为准则排序
multiset<Elem> //一个multiset,以less<>(operator<)为准则排序
multiset<Elem,op> //一个multiset,以op为准则排序
三、定义排序准则
1.以template参数定义
特点:只有排序准则相同的容器才能被合并
std::set<int,std::greater<int>> coll;
具体示例如下:
#include <iostream>
#include <string>
#include <deque>
#include <set>
#include <algorithm>
using namespace std;
/* class Person
*/
class Person {
private:
string fn; // first name
string ln; // last name
public:
Person() {
}
Person(const string& f, const string& n)
: fn(f), ln(n) {
}
string firstname() const;
string lastname() const;
// ...
};
inline string Person::firstname() const {
return fn;
}
inline string Person::lastname() const {
return ln;
}
ostream& operator<< (ostream& s, const Person& p)
{
s << "[" << p.firstname() << " " << p.lastname() << "]";
return s;
}
/* class for function predicate
* - operator () returns whether a person is less than another person
*/
class PersonSortCriterion {
public:
bool operator() (const Person& p1, const Person& p2) const {
/* a person is less than another person
* - if the last name is less
* - if the last name is equal and the first name is less
*/
return p1.lastname()<p2.lastname() ||
(p1.lastname()==p2.lastname() &&
p1.firstname()<p2.firstname());
}
};
int main()
{
Person p1("nicolai","josuttis");
Person p2("ulli","josuttis");
Person p3("anica","josuttis");
Person p4("lucas","josuttis");
Person p5("lucas","otto");
Person p6("lucas","arm");
Person p7("anica","holle");
// declare set type with special sorting criterion
typedef set<Person,PersonSortCriterion> PersonSet;
// create such a collection
PersonSet coll;
coll.insert(p1);
coll.insert(p2);
coll.insert(p3);
coll.insert(p4);
coll.insert(p5);
coll.insert(p6);
coll.insert(p7);
// do something with the elements
// - in this case: output them
cout << "set:" << endl;
PersonSet::iterator pos;
for (pos = coll.begin(); pos != coll.end(); ++pos) {
cout << *pos << endl;
}
}
2.以构造函数参数定义
特点:同一个型别可以运用不同的排序准则,而排序准则的初始值或状态也可以不同。如果执行期才获得排序准则,并且需要用到不同的排序准则(但数据型别必须相同)
实例如下:
//print.h
#include <iostream>
/* PRINT_ELEMENTS()
* - prints optional C-string optcstr followed by
* - all elements of the collection coll
* - separated by spaces
*/
template <class T>
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
typename T::const_iterator pos;
std::cout << optcstr;
for (pos=coll.begin(); pos!=coll.end(); ++pos) {
std::cout << *pos << ' ';
}
std::cout << std::endl;
}
#include <iostream>
#include <set>
#include "print.h"
using namespace std;
// type for sorting criterion
template <class T>
class RuntimeCmp {
public:
enum cmp_mode {normal, reverse};
private:
cmp_mode mode;
public:
// constructor for sorting criterion
// - default criterion uses value normal
RuntimeCmp (cmp_mode m=normal) : mode(m) {
}
// comparison of elements
bool operator() (const T& t1, const T& t2) const {
return mode == normal ? t1 < t2 : t2 < t1;
}
// comparison of sorting criteria
bool operator== (const RuntimeCmp& rc) {
return mode == rc.mode;
}
};
// type of a set that uses this sorting criterion
typedef set<int,RuntimeCmp<int> > IntSet;
// forward declaration
void fill (IntSet& set);
int main()
{
// create, fill, and print set with normal element order
// - uses default sorting criterion
IntSet coll1;
fill(coll1);
PRINT_ELEMENTS (coll1, "coll1: ");
// create sorting criterion with reverse element order
RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse);
// create, fill, and print set with reverse element order
IntSet coll2(reverse_order);
fill(coll2);
PRINT_ELEMENTS (coll2, "coll2: ");
// assign elements AND sorting criterion
coll1 = coll2;
coll1.insert(3);
PRINT_ELEMENTS (coll1, "coll1: ");
// just to make sure...
if (coll1.value_comp() == coll2.value_comp()) {
cout << "coll1 and coll2 have same sorting criterion"
<< endl;
}
else {
cout << "coll1 and coll2 have different sorting criterion"
<< endl;
}
}
void fill (IntSet& set)
{
// fill insert elements in random order
set.insert(4);
set.insert(7);
set.insert(5);
set.insert(1);
set.insert(6);
set.insert(2);
set.insert(5);
}
四、非变动性操作
用来查询大小、相互比较
c.size() //返回当前元素数量
c.empty() //判断大小是否为0
c.max_size() //返回可容纳的元素最大数量
五、特殊的搜寻函数
count(elem) //返回元素值为elem的元素个数
find(elem) //返回元素值为elem的第一个元素,如果找不到就返回end()
lower_bound(elem) //返回elem的第一个可安插位置,也就是“元素值>=elem”的第一个元素位置
upper_bound(elem) //返回elem的最后一个可安插位置,也就是“元素值>elem”的第一个元素位置
equal_range(elem) //返回elem可安插的第一个位置和最后一个位置,也就是“元素值==elem”的元素区间
运行实例:
#include <iostream>
#include <set>
using namespace std;
int main ()
{
set<int> c;
c.insert(1);
c.insert(2);
c.insert(4);
c.insert(5);
c.insert(6);
set<int>::iterator it = c.begin();
while (it != c.end())
{
cout<<*it++<<' ';
}
cout<<endl;
cout << "lower_bound(3): " << *c.lower_bound(3) << endl;
cout << "upper_bound(3): " << *c.upper_bound(3) << endl;
cout << "equal_range(3): " << *c.equal_range(3).first << " "
<< *c.equal_range(3).second << endl;
cout << endl;
cout << "lower_bound(5): " << *c.lower_bound(5) << endl;
cout << "upper_bound(5): " << *c.upper_bound(5) << endl;
cout << "equal_range(5): " << *c.equal_range(5).first << " "
<< *c.equal_range(5).second << endl;
}
六、赋值操作
c1 = c2 //将c2的元素全部赋值给c1
c1.swap(c2);
swap(c1,c2);
七、迭代器
c.begin() //返回一个随机存取迭代器,指向第一个元素
c.end() //返回一个随机存取迭代器,指向最后元素的下一位置
c.rbegin() //返回一个逆向迭代器,指向逆向迭代的第一个元素
c.rend() //返回一个逆向迭代器,指向逆向迭代的最后元素的下一位置
八、安插和移除
c.insert(elem) //安插一份elem副本,返回新元素位置
c.insert(pos,elem) //安插一份elem副本,返回新元素位置(pos是个提示,指出安插操作的搜寻七点)
c.insert(beg,end) //将区间[beg,end]内所有元素的副本安插到c(无返回值)
c.erase(elem) //移除“与elem相等”的所有元素,返回被移除的元素个数
c.erase(pos) //移除迭代器pos所在位置上的元素(无返回值)
c.erase(beg,end) //移除区间[beg,end]内的所有元素,无返回值
c.clear() //移除全部元素,将整个容器清空
注意:安插函数的返回值不同
1.set提供如下接口:
pair<iterator,bool> insert(const value_type& elem);
iterator insert(iterator pos_hint,const value_type& elem);
2.multiset提供如下接口:
iterator insert(const value_type& elem);
iterator insert(iterator pos_hint,const value_type& elem);
返回值不同的原因:因为multiset允许元素重复,而set不允许,所以需要pair对来进行组织判断:
pair中的second用来表示安插是否成功
pair中的first成员返回新元素位置或返回现存的同值元素的位置(如果set已含同值元素)。
九、运行实例
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
/* type of the collection:
* - no duplicates
* - elements are integral values
* - descending order
*/
typedef set<int,greater<int> > IntSet;
IntSet coll1; // empty set container
// insert elements in random order
coll1.insert(4);
coll1.insert(3);
coll1.insert(5);
coll1.insert(1);
coll1.insert(6);
coll1.insert(2);
coll1.insert(5);
// iterate over all elements and print them
IntSet::iterator pos;
for (pos = coll1.begin(); pos != coll1.end(); ++pos) {
cout << *pos << ' ';
}
cout << endl;
// insert 4 again and process return value
pair<IntSet::iterator,bool> status = coll1.insert(4);
if (status.second) {
cout << "4 inserted as element "
<< distance(coll1.begin(),status.first) + 1
<< endl;
}
else {
cout << "4 already exists" << endl;
}
// assign elements to another set with ascending order
set<int> coll2(coll1.begin(),
coll1.end());
// print all elements of the copy
copy (coll2.begin(), coll2.end(),
ostream_iterator<int>(cout," "));
cout << endl;
// remove all elements up to element with value 3
coll2.erase (coll2.begin(), coll2.find(3));
// remove all elements with value 5
int num;
num = coll2.erase (5);
cout << num << " element(s) removed" << endl;
// print all elements
copy (coll2.begin(), coll2.end(),
ostream_iterator<int>(cout," "));
cout << endl;
}
如果是multiset,则只需做稍微改动:
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
/* type of the collection:
* - duplicates allowed
* - elements are integral values
* - descending order
*/
typedef multiset<int,greater<int> > IntSet;
IntSet coll1; // empty multiset container
// insert elements in random order
coll1.insert(4);
coll1.insert(3);
coll1.insert(5);
coll1.insert(1);
coll1.insert(6);
coll1.insert(2);
coll1.insert(5);
// iterate over all elements and print them
IntSet::iterator pos;
for (pos = coll1.begin(); pos != coll1.end(); ++pos) {
cout << *pos << ' ';
}
cout << endl;
// insert 4 again and process return value
IntSet::iterator ipos = coll1.insert(4);
cout << "4 inserted as element "
<< distance(coll1.begin(),ipos) + 1 << endl;
// assign elements to another multiset with ascending order
multiset<int> coll2(coll1.begin(),
coll1.end());
// print all elements of the copy
copy (coll2.begin(), coll2.end(),
ostream_iterator<int>(cout," "));
cout << endl;
// remove all elements up to element with value 3
coll2.erase (coll2.begin(), coll2.find(3));
// remove all elements with value 5
int num;
num = coll2.erase (5);
cout << num << " element(s) removed" << endl;
// print all elements
copy (coll2.begin(), coll2.end(),
ostream_iterator<int>(cout," "));
cout << endl;
}