C++STL学习(4)容器set和multiset

注:博客内容均来自于对《C++标准库》侯捷,华中科技大学出版社一书的笔记。转载请注明出处。

所有例程在Red Hat Linux 3.2.2-5版本上编译运行,g++的版本是 g++ (GCC) 3.2.2 20030222。


1、set和multiset

  set和multiset里面的元素都是“有序的”。因为set和multiset会根据特定的排序准则,自动将元素排序。不同的是set容器里面不允许有重复的元素,multiset容器允许存在重复的元素。
   set和multiset通常都是以平衡二叉树来实现的。(这是根据他们各项操作的复杂度得出的结论,C++标准规格书中并没有说明这一点!)
   实际上,set和multiset通常以红黑树(red-black tree)实现的。红黑树在改变元素数量和元素搜索方面表现都很出色,它保证节点安插时最多只会作两个重新连接(relink)动作,而且到达某一元素的最长路径深度,最多只是最短路径的两倍。


自动排序的主要优点在于使二叉树查找元素时具有良好的性能。其查找算法具有对数复杂度!
但是,自动排序造成set和multiset的一个重要限制:不能直接改变元素值,因为这样会打乱原本的正确顺序,因此,要改变元素值,必须先删除旧元素,在插入新元素,因此:
1:set和multiset一样,不提供用来直接存取元素的任何操作函数;
2:通过迭代器进行元素的间接存取,有一个限制:元素值是常数



2、set和multiset的操作函数

2.1 创建、构造和析构


排序准则可以这样定义:
1> 以template参数定义之。 
std::set<int, std::geater<int> > col1;

第二个参数排序准则的型别,实际的排序准则是容器所产生的仿函数。下面一个例子来说明这种方式。

example:

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

class Person
{
public:
	Person(string a,string b) : 
	       strFirstname(a),strLastname(b)
	{}
public:
	string firstname() const
	{
		return strFirstname;
	}
	string lastname() const
	{
		return strLastname;
	}
private:
	const string strFirstname;
	const string strLastname;
};


//仿函数实现自定义排序
class PersonSortCriterion
{
public :
	bool operator()(const Person &p1, const Person &p2)
	{
		return (p1.lastname() < p2.lastname() ||
			(!(p2.lastname() < p1.lastname()) && 
			p1.firstname() < p2.firstname()));
	}
};


int main(int argc, char *argv[])
{
	typedef set<Person, PersonSortCriterion> PersonSet;
	PersonSet col1;
	//创建元素,并添加到容器
	Person p1("Jay","Chou");
	Person p2("Robin","Chou");
	Person p3("Robin","Lee");
	Person p4("Bob","Smith");
	col1.insert(p1);
	col1.insert(p2);
	col1.insert(p3);
	col1.insert(p4);
	PersonSet::iterator pos;
	//输出PersonSet中的所有元素
	for(pos = col1.begin(); pos != col1.end(); ++pos)
	{
		cout<<pos->firstname()<< " " << pos->lastname() << endl;
	}
	cout<<endl;
	return 0;
}

2> 以构造函数定义之。
这种情况下,同一个型别可以运行不同的排序准则,而排序的初始值或者状态也可以不同。

如果执行期间才获得排序准则,而且需要用到不同的排序准则,那么使用这种方式再好不过了!

example:

#include <iostream>
#include <set>
#include "print.h"
using namespace std;

template <class 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) const
	{
		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& set)
{
	set.insert(4);
	set.insert(7);
	set.insert(5);
	set.insert(1);
	set.insert(6);
	set.insert(2);
	set.insert(5);
}


int main(int argc, char *argv[])
{
	IntSet col1;
	fill(col1);
	PRINT_ELEMENTS(col1, "col1: ");

	RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse);

	IntSet col2(reverse_order);
	fill(col2);
	PRINT_ELEMENTS(col2, "col2: ");

	col1= col2;
	col1.insert(3);
	PRINT_ELEMENTS(col1, "col1: ");

	if(col1.value_comp() == col2.value_comp())
	{
		cout<<"col1 == col2"<<endl;
	}
	else
	{
		cout<<"col1 != col2"<<endl;
	}
	return 0;
}

注:比较操作只能比较类型相同的容器。不同类型的容器比较会出错!!






3、例子

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

int main(int argc, char *argv[])
{
	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 << " ";
	}
	cout<< endl;
	
	pair<IntSet::iterator, bool> status = col1.insert(4);
	if(status.second)
	{
		cout<< "4 inset as a element " 
			<< distance(col1.begin(), status.first) + 1
			<< endl;
	}
	else
		cout<< "4 already exists "<<endl;

	set<int> col2(col1.begin(),
		          col1.end());

	copy(col2.begin(),col2.end(),
		ostream_iterator<int>(cout," "));
	cout<<endl;

	col2.erase(col2.begin(), col2.find(3));

	int num;
	num = col2.erase(5);
	cout<<num<<"element(s) removed"<<endl;
	copy(col2.begin(),col2.end(),
		ostream_iterator<int>(cout," "));
	cout<<endl;
	return 0;
}
运行结果





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空空的司马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值