C++ STL一一set和multiset

一、特点

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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值