STL源码剖析:4.关联式容器(上)


1.简介

	除了常见的序列式容器之外,我们也经常使用关联式问题来解决一些问题,关联式容器相比较
序列式容器而言,其主要特性就是它可以通过键值对容器内部的元素来进行索引。

2.RB-tree

2.1 简介
在序列式容器中很大一部分都是通过底层使用红黑树来实现的,所谓红黑树首先他是一个二叉搜索树,树上的每一个结点不是红色就是黑色,并且它还需要满足以下性质:(我们将NULL视为黑色的结点)
1.每个结点b不是红色就是黑色。
2.根节点为黑色。
3.如果某一个结点为红色,那么其子节点必定为黑色。
4.任意一个结点到NULL的任何路径上,其黑节点数目必定是相同的。

2.2 红黑树的迭代器
在任意一个容器的设计中,我们的迭代器的作用都是用来访问容器中的元素,因此在设计的过程中,就需要根据容器的类型来设计不同的迭代器,来完成相应的元素访问操作。
在SGI STL的版本中,红黑树的迭代器实现分为两层,它属于双向迭代器,但是不具备随机访问的功能,与list十分相似,RB-tree的迭代器继承基础迭代器,并使用基础迭代器中的函数来完成相应的+±-操作:

	//++操作就是寻找比当前结点大的最小的结点
	void increment() {
		if (node->right != 0) {				//如果有右子节点 状况(1)
			node = node->right;				//就向右走
			while (node->left != nullptr) { //然后一直往左子树走到底
				node = node->left;			//即是解答
			}
		}
		else {								//没有右子节点 状况(2)
			base_ptr y = node->parent;		//找出父节点
			while (node == y->right) {		//如果现行结点本身就是一个右子节点
				node = y;					//就一直上溯 直到不为右子节点为止
				y = y->parent;
			}
			if (node->right != y) node = y;	//若此时右子节点不等于此时的父节点 状况(3)此时的父节点即为答案 否则此时的node为解答,状况(4)
		}
	}

	/*	注意 以上判断“若此时的右子节点不等于此时的父节点”,是为了应付一种
	*	特殊情况:我们欲寻找根结点的下一节点,而恰巧根节点无右子节点。当然
	*	以上特殊做法必须配合RB-tree 根结点与特殊之header之间的特殊关系
	*/

	//--操作就是寻找比当前结点小的最大的数
	void decrement() {
		if (node->color == _rb_tree_red && node->parent->parent == node)	//如果是红结点 且父节点的父节点等于自己
			node = node->right;												//状况(1)右节点即为解答
		//以上情况发生于node为header时,即(node为end()时)
		//注意:header之右节点即mpstright,指向整棵树的max结点
		else if (node->left != 0) {		//如果有左子节点 状况(2)
			base_ptr y = node->left;	//令y指向左子节点
			while (y->right != 0)		//当y有右子节点时
				y = y->right;			//一直往右子节点走到底
			node = y;					//最后即为答案
		}
		else {
			base_ptr y = node->parent;	//既非根节点 亦无左子节点
			while (node == y->left) {	//状况3找出父节点
				node = y;				//当现行结点为左子节点
				y = y->parent;			//一直交替往上走,直到现行结点不为左子结点
			}
			node = y;					//此时父节点即为答案
		}
	}

2.3 RB-tree的数据结构
在探索一个容器之前,我们会对于其内部的成员数据十分好奇,在SGI STL中RB-tree一共有三个成员数据,分别来表示树的结点数量,一个header(特殊的实现,其左右子节点分别指向最大值和最小值),以及一个函数指针(用于接收传入的比较键值的函数)。

template<class Key, class Value, class KeyValue, class Compare, class Alloc = alloc>
class rb_tree
{
protected:
	typedef rb_tree_value_traits<T> value_traits;
	typedef void* void_pointer;
	typedef _rb_tree_node_base* base_ptr;
	typedef _rb_tree_node<Value> rb_tree_node;
	typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
	typedef _rb_tree_color_type color_type;
public:
	typedef Key key_type;
	typedef Value value_type;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type const_reference;
	typedef rb_tree_node* link_type;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
protected:

	//开辟一个结点
	link_type get_node() {
		return rb_tree_node_allocator::allocate();
	}
	//释放一个结点
	link_type put_node(link_type p) {
		rb_tree_node_allocator::deallocate(p);
	}
	//创建一个带值的结点
	link_type create_node(const value_type& x) {
		link_type tmp = get_node();
		construct(&tmp->value_field, x);
		return tmp;
	}
	//复制一个结点
	link_type clone_node(link_type x) {
		link_type tmp = create_node(x->value_field);
		tmp->color = x->color;
		tmp->left = 0;
		tmp->right = 0;
		return tmp;
	}
	//释放
	void destroy_node(link_type p) {
		destroy(&p->value_field);
		put_node(p);
	}
protected:
	size_type node_count;
	//一种特殊处理 其左子节点表示最小值 右子节点表示最大值
	link_type header;
	Compare key_compare;

	//用以下三个函数取得header的成员
	link_type root() const {
		return (link_type)header->parent;
	}

	link_type leftmost() const {
		return (link_type)header->left;
	}

	link_type rightmost() const {
		return (link_type)header->right;
	}

	//以下取得结点x
	static link_type& left(link_type x) {
		return (link_type&)(x->left);
	}

	static link_type& right(link_type x) {
		return (link_type&)(x->right);
	}

	static link_type& parent(link_type x) {
		return (link_type&)(x->parent);
	}

	static reference value(link_type x) {
		return x->value_field;
	}

	static Key& key(link_type x) {
		return KeyValue()(value(x));
	}

	static color_type& color(link_type x) {
		return (color_type&)(x->color);
	}

	//以下也是为了方便取得结点X的成员
	static link_type& left(base_ptr x) {
		return (link_type&)(x->left);
	}

	static link_type& right(base_ptr x) {
		return (link_type&)(x->right);
	}

	static link_type& parent(base_ptr x) {
		return (link_type&)(x->parent);
	}

	static reference value(base_ptr x) {
		return (link_type)x->value_field;
	}

	static Key& key(base_ptr x) {
		return KeyValue()(value(link_type(x)));
	}

	static color_type& color(base_ptr x) {
		return (color_type&)(link_type(x)->color);
	}

	//求极大值和极小值
	static link_type minimum(link_type x) {
		return (link_type)_rb_tree_node_base::minimum(x);
	}
	static link_type maximum(link_type x) {
		return (link_type)_rb_tree_node_base::maximum(x);
	}
};

2.4 RB-tree的元素操作
2.4.1 元素的查找操作
在红黑树中,除了常见的find()操作以外,还有lower_bound()、upper_bound()以及equal_range操作来进行查找操作,这几个操作也是后序中的set以及map中会调用的操作,因此代码如下所示:

//*********************lower_bound()**************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
lower_bound(const key_type& key)
{
	auto y = header;
	auto x = root();
	while (x != nullptr)
	{
		if (!key_comp(value_traits::get_key(x->get_node_ptr()->value), key))
		{ // x的value与key比较 如果x大于等于key的话就往左走,否则就往右边走
			y = x, x = x->left;
		}
		else
		{
			x = x->right;
		}
	}
	return iterator(y);
}

//**********************upper_bound()****************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
upper_bound(const key_type& key)
{
	auto y = header;
	auto x = root();
	while (x != nullptr)
	{
		if (key_comp(key, value_traits::get_key(x->get_node_ptr()->value)))
		{ // key < x 于上述刚好相反
			y = x, x = x->left;
		}
		else
		{
			x = x->right;
		}
	}
	return iterator(y);
}
//*********************equal_range()****************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
ministl::pair<iterator, iterator>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::equal_range(const key_type& key) {
		return ministl::pair<iterator, iterator>(lower_bound(key), upper_bound(key));
}

2.4.2 元素的插入操作
在红黑树的实现中,一共有两种不同的插入方式:insert_unique()和insert_equal()操作,前者表示被插入结点的键值在整棵树中必须独一无二,后者表示被插入的键值在整棵树中可以重复。

//***************************insert_equal()*******************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator 
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_equal(const value_type& v) {
	link_type y = header;
	link_type x = root();
	
	while (x != 0) {
		y = x;
		x = key_compare(KeyOfValue()(v), key(x)) ? left(x) : right(x);
		//以上,遇大则往左边,遇小或者等于则往右
		//注:这里的大小比较是v与x进行比较,如果v大于x的话,那么v遇大就往左,否则就往右
	}
	//以x为新值插入点,y为插入点的父节点,v为新值
	return _insert(x, y, v);
}

//***************************insert_unique()*******************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
pair<typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator, bool>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_unique(const value_type& v) {
	link_type y = header;
	link_type x - root();
	bool comp = true;
	while (x != 0)
	{
		y = x;
		comp = key_compare(KeyOfValue()(v), key(x));
		x = comp ? left(x) : right(x);
	}
	//同样的遇到大的往左 遇到小的往右
	iterator j = iterator(y);//令迭代器指向插入点的父节点
	if (comp) {//如果离开循环时comp为true表示在插入点的左侧
		if (j == begin()) {
			//如果插入点是最左侧
			//x为插入点,y为插入点的父节点,v为新值
			return pair<iterator, bool>(_insert(x, y, v), true);
		}
		else {
			--j;
		}
	}
	//小于新值 表示遇到小 将插于右侧
	if (key_compare(key(j->node), KeyOfValue()(v)) {
		return pair<iterator, bool>(_insert(x, y, v), true);
	}

	return pair<iterator, bool>(j, false);
}

其中,真正执行插入操作的是函数_insert()操作:

template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
iterator rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
_insert(base_ptr x_, base_ptr y_, const value_type& v) {
	//x新值插入点 y是插入点的父节点 v是新值
	link_type x = (link_type)x_;
	link_type y = (link_type)y_;
	link_type z;

	//是键值比较大小准则 
	if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {
		z = create_node(v);
		left(y) = z;//这使得当y即为header()时,leftmost() = z;
		if (y == header) {
			root() = z;
			rightmost() = z;
		}
		else if (y == leftmost()){ //如果y为最左结点
			leftmost() = z;//维护leftmost使它永远指向最左节点
		}
	}
	else {
		z = create_node(v);
		right(y) = z;
		if (y == rightmost()) //同样的维护rightmost节点
			rightmost() = z;
	}

	parent(z) = y;//设定新的父节点
	left(z) = 0;//设定新结点的左子节点
	right(z) = 0;//设定新结点的右子节点

	//调整新加入的节点颜色
	_rb_tree_rebalance(z, header->parent);
	//增加节点数目
	++node_count;
	return iterator(z);
}

2.4.3 插入操作后结点元素的变化操作
在红黑树中,每个插入的结点都是默认是红色的(不可以为黑色,因为根据红黑树的规定而言,如果插入的每一个结点都是黑色的话,也是会满足那几个规则,但是在这个时候红黑树的所有的结点都是黑色的了,就变成了一颗普通的二叉搜索树,没有那些特殊的性质了)。
进行插入操作后,当前被插入的结点有几种情况:
①:如果结点的父节点以及叔叔结点都是红色,那么就将父节点以及叔叔结点都变为黑色,然后将爷爷结点的颜色变为红色。
②:如果插入的结点的父节点的颜色是红色,叔叔结点的颜色是黑色,并且当前结点是右子节点,那么久进行一次左旋操作。
③:如果插入结点的父节点的颜色是红色,叔叔结点的颜色是黑色,并且当前结点是左子节点,那么就进行一次右旋操作。

//************************_rb_tree_rebalance()*****************************
inline void _rb_tree_rebalance(_rb_tree_node_base* x, _rb_tree_node_base* &root) {
	x->color = _rb_tree_red;
	while (x != root && x->parent->color == _rb_tree_red) {
		if (x->parent == x->parent->parent->left) {
			_rb_tree_node_base* y = x->parent->parent->right;
			if (y && y->color == _rb_tree_red) {
				x->parent->color == _rb_tree_black;
				y->color = _rb_tree_black;
				x->parent->parent->color = _rb_tree_red;
				x = x->parent->parent;
			}
			else {
				if (x == x->parent->right) {
					x = x->parent;
					_rb_tree_rotate_left(x, root);//左旋
				}

				//与左旋相比,右旋稍微麻烦一些,就是要将其父节点变为黑色,将爷爷节点变为红色
				x->parent->color = _rb_tree_black;
				x->parent->parent->color = _rb_tree_red;
				_rb_tree_rotate_right(x->parent->parent, root);//右旋
			}
		}
		else {
			_rb_tree_node_base* y = x->parent->parent->left;
			if (y && y->color == _rb_tree_red) {
				x->parent->color = _rb_tree_black;
				y->color = _rb_tree_black;
				x->parent->parent->color = _rb_tree_red;
				x = x->parent->parent;
			}
			else {
				if (x == x->parent->left) {
					x = x->parent;
					_rb_tree_rotate_right(x, root);
				}
				x->parent->color = _rb_tree_black;
				x->parent->parent->color = _rb_tree_red;
				_rb_tree_rotate_left(x->parent->parent, root);
			}
		}
	}

	root->color = _rb_tree_black;
}

2.4.4 红黑树的旋转操作
①:左旋:
Ⅰ.改变旋转点的右子节点的左子节点指向旋转点的右子节点
Ⅱ.改变旋转点及其2右子节点的位置,原本的旋转点的右子节点变为之前旋转点所在的位置,原本的旋转变为变化后的根节点的左子树。
Ⅲ.更新之前的结点
②:右旋:
Ⅰ:将插入点的父节点的颜色改为黑色,然后再将其爷爷结点变为红色,将其爷爷结点作为旋转点。
Ⅱ:改变旋转点的左子节点的右子节点指向旋转点的左子节点。
Ⅲ.改变旋转点及其左子节点的位置,原本的旋转点的左子节点变为之前旋转点的位置,然后将旧的旋转点变为新旋转点的右子树。
Ⅳ.更新之前的结点。

//****************************_rb_tree_rotate_left()************************************
inline void _rb_tree_rotate_left(_rb_tree_node_base* x, _rb_tree_node_base*& root) {

	_rb_tree_node_base* y = x->right;
	x->right = y->left;
	if (y->left != 0) {
		y->left->right = x;
	}
	y->parent = x->parent;

	if (x == root)
		root = y;
	else if (x == x->parent->left)
		x->parent->left = y;
	else
		x->parent->right = y;

	y->left = x;
	x->parent = y;
}

//****************************_rb_tree_rotate_right()************************************
inline void _rb_tree_rotate_right(_rb_tree_node_base* x, _rb_tree_node_base*& root) {

	_rb_tree_node_base* y = x->left;
	x->left = y->right;
	if (y->right != 0)
		y->right->parent = x;
	y->parent = x->parent;

	if (x == root) {
		root = y;
	}
	else if (x == x->parent->right)
		x->parent->right = y;
	else
		x->parent->left = y;

	y->right = x;
	x->parent = y;
}

2.4.5 删除结点后保持红黑树平衡
如果我们要删除的结点为红色,则就按照二叉查找树的删除即可,不会破坏树本身的性质,但是如果我们要删除的结点为黑色的话,并且该节点为左子节点(右子节点情况与下述相反):
①:兄弟结点若为红色,令父节点为红色,兄弟结点为黑色,然后进行旋转处理
②:兄弟结点若为黑色,并且兄弟结点的两个子结点都为黑色,令兄弟结点变为红色,令父亲结点变为当前结点继续处理。
③:兄弟结点为黑色,左子节点位红色,其右子节点位黑色,令兄弟结点为红色,兄弟结点的左子节点为黑色,以兄弟结点为旋转点右旋,继续处理。
④:兄弟结点为黑色,右子节点位红色,令兄弟结点为父亲结点的颜色,父亲结点为黑色,兄弟结点的右子结点为黑色,以父亲节点为旋转点左旋。

// 删除节点后使 rb tree 重新平衡,参数一为要删除的节点,参数二为根节点,参数三为最小节点,参数四为最大节点
// 
// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630
//          http://blog.csdn.net/v_JULY_v/article/details/6109153
template <class NodePtr>
NodePtr _rb_tree_erase_rebalance(NodePtr z, NodePtr& root, NodePtr& leftmost, NodePtr& rightmost)
{
	// y 是可能的替换节点,指向最终要删除的节点
	auto y = (z->left == nullptr || z->right == nullptr) ? z : rb_tree_next(z);
	// x 是 y 的一个独子节点或 NIL 节点
	auto x = y->left != nullptr ? y->left : y->right;
	// xp 为 x 的父节点
	NodePtr xp = nullptr;

	// y != z 说明 z 有两个非空子节点,此时 y 指向 z 右子树的最左节点,x 指向 y 的右子节点。
	// 用 y 顶替 z 的位置,用 x 顶替 y 的位置,最后用 y 指向 z
	if (y != z)
	{
		z->left->parent = y;
		y->left = z->left;

		// 如果 y 不是 z 的右子节点,那么 z 的右子节点一定有左孩子
		if (y != z->right)
		{ // x 替换 y 的位置
			xp = y->parent;
			if (x != nullptr)
				x->parent = y->parent;

			y->parent->left = x;
			y->right = z->right;
			z->right->parent = y;
		}
		else
		{
			xp = y;
		}

		// 连接 y 与 z 的父节点 
		if (root == z)
			root = y;
		else if (rb_tree_is_lchild(z))
			z->parent->left = y;
		else
			z->parent->right = y;
		y->parent = z->parent;
		mystl::swap(y->color, z->color);
		y = z;
	}
	// y == z 说明 z 至多只有一个孩子
	else
	{
		xp = y->parent;
		if (x)
			x->parent = y->parent;

		// 连接 x 与 z 的父节点
		if (root == z)
			root = x;
		else if (rb_tree_is_lchild(z))
			z->parent->left = x;
		else
			z->parent->right = x;

		// 此时 z 有可能是最左节点或最右节点,更新数据
		if (leftmost == z)
			leftmost = x == nullptr ? xp : rb_tree_min(x);
		if (rightmost == z)
			rightmost = x == nullptr ? xp : rb_tree_max(x);
	}
	// 此时,y 指向要删除的节点,x 为替代节点,从 x 节点开始调整。
// 如果删除的节点为红色,树的性质没有被破坏,否则按照以下情况调整(x为左子节点为例)
	if (!rb_tree_is_red(y))
	{ // x 为黑色时,调整,否则直接将 x 变为黑色即可
		while (x != root && (x == nullptr || !rb_tree_is_red(x)))
		{
			if (x == xp->left)
			{ // 如果 x 为左子节点
				auto brother = xp->right;
				if (rb_tree_is_red(brother))
				{ // case 1
					rb_tree_set_black(brother);
					rb_tree_set_red(xp);
					_rb_tree_rotate_left(xp, root);
					brother = xp->right;
				}
				// case 1 转为为了 case 2、3、4 中的一种
				if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) &&
					(brother->right == nullptr || !rb_tree_is_red(brother->right)))
				{ // case 2
					rb_tree_set_red(brother);
					x = xp;
					xp = xp->parent;
				}
				else
				{
					if (brother->right == nullptr || !rb_tree_is_red(brother->right))
					{ // case 3
						if (brother->left != nullptr)
							rb_tree_set_black(brother->left);
						rb_tree_set_red(brother);
						_rb_tree_rotate_right(brother, root);
						brother = xp->right;
					}
					// 转为 case 4
					brother->color = xp->color;
					rb_tree_set_black(xp);
					if (brother->right != nullptr)
						rb_tree_set_black(brother->right);
					_rb_tree_rotate_left(xp, root);
					break;
				}
			}
			else  // x 为右子节点,对称处理
			{
				auto brother = xp->left;
				if (rb_tree_is_red(brother))
				{ // case 1
					rb_tree_set_black(brother);
					rb_tree_set_red(xp);
					_rb_tree_rotate_right(xp, root);
					brother = xp->left;
				}
				if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) &&
					(brother->right == nullptr || !rb_tree_is_red(brother->right)))
				{ // case 2
					rb_tree_set_red(brother);
					x = xp;
					xp = xp->parent;
				}
				else
				{
					if (brother->left == nullptr || !rb_tree_is_red(brother->left))
					{ // case 3
						if (brother->right != nullptr)
							rb_tree_set_black(brother->right);
						rb_tree_set_red(brother);
						_rb_tree_rotate_left(brother, root);
						brother = xp->left;
					}
					// 转为 case 4
					brother->color = xp->color;
					rb_tree_set_black(xp);
					if (brother->left != nullptr)
						rb_tree_set_black(brother->left);
					_rb_tree_rotate_right(xp, root);
					break;
				}
			}
		}
		if (x != nullptr)
			rb_tree_set_black(x);
	}
	return y;
}

3.map/multimap容器和set/multiset容器

以下容器有点类似于之前介绍的queue以及stack容器,类似于一种容器适配器,因此我们就不多介绍了。

3.1 set容器/multiset容器
set容器的特性是所有元素会被自动排序,set 的键值就是实值,实值就是键值,并且不允许有两个具有相同键值的值,我们不可以随意改变set容器中的值,因为都是按照元素大小排序好的,如果随意改变的话排序规则就会发生变化。
multiset容器与set容器稍微有所不同,不同之处在于它允许键值相同的元素存入容器中。

//******************************  set  ****************************
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set
{
public:
	typedef Key key_type;
	typedef Key value_type;
	typedef Compare key_compare;
	typedef Compare value_compare;
private:

	typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;
	rep_type t; //采用红黑树来表现set

public:
	typedef typename rep_type::const_pointer pointer;
	typedef typename rep_type::const_pointer const_pointer;
	typedef typename rep_type::const_reference reference;
	typedef typename rep_type::const_reference const_reference;
	typedef typename rep_type::const_iterator iterator;

	typedef typename rep_type::const_iterator const_iterator;
	typedef typename rep_type::const_reverse_iterator reverse_iterator; 
	typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
	typedef typename rep_type::size_type size_type;
	typedef typename rep_type::differnece_type difference_type;

	//构造函数
	//在set容器中 一定使用的是rb_tree的insert_unique()而不是insert_equal()
	//multiset才使用rb_tree的insert_equal()
	//因为set不允许重复的键值存在
	set():t(Compare()){ }
	explicit set(const Compare& comp) : t(comp) {}

	template<class InputIterator>
	set(InputIterator first, InputIterator last) :t(Compare()){
		t.insert_unique(first, last);
	}

	template<class InputIterator>
	set(InputIterator first, InputIterator last, const Compare& comp):t(comp){
		t.insert_unique(first, last);
	}

	set(const set<Key, Compare, Alloc>& x):t(x.t) { }
	set<Key, Compare, Alloc>& operator=(const set<Key, Compare, Alloc>& x) {
		t = x.t;
		return *this;
	}

	//元素操作
	key_compare key_comp() const {
		return t.key_comp();
	}

	value_compare value_comp() const {
		return t.key_comp();
	}

	iterator begin() const {
		return t.begin();
	}

	iterator end() const {
		return t.end();
	}

	reverse_iterator rbegin() const {
		return t.rbegin();
	}

	reverse_iterator rend() const {
		return t.rend();
	}

	bool empty() const {
		return t.empty();
	}

	size_type size() const {
		return t.size();
	}

	size_type max_size() const {
		return t.max_size();
	}

	void swap(set<Key, Compare, Alloc>& x) {
		t.swap(x.t);
	}

	//insert/以及erase操作
	typedef pair<iterator, bool> pair_iterator_bool;
	pair<iterator, bool> insert(const value_type& x) {
		pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
		return pair<iterator, bool>(p.first, p.second);
	}

	iterator insert(iterator position, const value_type& x) {
		typedef typename rep_type::iterator rep_iterator;
		return t.insert_unique((rep_iterator&)position, x);
	}

	template<class InputIterator>
	void insert(InputIterator first, InputIterator last) {
		t.insert_unique(first, last);
	}

	void erase(iterator position) {
		typedef typename rep_type::iterator rep_iterator;
		t.erase((rep_iterator&)position);
	}

	size_type erase(const key_type& x) {
		return t.erase(x);
	}

	void erase(iterator first, iterator last) {
		typedef typename rep_type::iterator rep_iterator;
		t.erase((rep_iterator&)first, (rep_iterator&)last);
	}

	void clear() {
		t.clear();
	}

	//set operations
	iterator find(const key_type& x) const {
		return t.find(x);
	}

	size_type count(const key_type& x) const {
		return t.size(x);
	}

	iterator lower_bound(const key_type& x) const {
		return t.lower_bound(x);
	}

	iterator upper_bound(const key_type& x) const {
		return t.upper_bound(x);
	}
	
	pair<iterator, iterator> equal_range(const key_type& x) const {
		return t.equal_range_unique(x);
	}

	friend bool operator==(const set& lhs, const set& rhs) { return lhs.t == rhs.t; }
	friend bool operator< (const set& lhs, const set& rhs) { return lhs.t < rhs.t; }
};
// 重载比较操作符
template <class Key, class Compare, class Alloc>
bool operator==(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
	return lhs == rhs;
}

template <class Key, class Compare, class Alloc>
bool operator<(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
	return lhs < rhs;
}

template <class Key, class Compare, class Alloc>
bool operator!=(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
	return !(lhs == rhs);
}

template <class Key, class Compare, class Alloc>
bool operator>(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
	return rhs < lhs;
}

template <class Key, class Compare, class Alloc>
bool operator<=(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
	return !(rhs < lhs);
}

template <class Key, class Compare, class Alloc>
bool operator>=(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
	return !(lhs < rhs);
}

//*******************************  multiset  ****************************
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class multiset
{
public:
	typedef Key key_type;
	typedef Key value_type;
	typedef Compare key_compare;
	typedef Compare value_compare;
private:

	typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;
	rep_type t; //采用红黑树来表现set

public:
	typedef typename rep_type::const_pointer pointer;
	typedef typename rep_type::const_pointer const_pointer;
	typedef typename rep_type::const_reference reference;
	typedef typename rep_type::const_reference const_reference;
	typedef typename rep_type::const_iterator iterator;

	typedef typename rep_type::const_iterator const_iterator;
	typedef typename rep_type::const_reverse_iterator reverse_iterator;
	typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
	typedef typename rep_type::size_type size_type;
	typedef typename rep_type::differnece_type difference_type;

	//构造函数
	//在set容器中 一定使用的是rb_tree的insert_unique()而不是insert_equal()
	//multiset才使用rb_tree的insert_equal()
	//因为set不允许重复的键值存在
	multiset() :t(Compare()) { }
	explicit multiset(const Compare& comp) : t(comp) {}

	template<class InputIterator>
	multiset(InputIterator first, InputIterator last) : t(Compare()) {
		t.insert_equal(first, last);
	}

	template<class InputIterator>
	multiset(InputIterator first, InputIterator last, const Compare& comp) : t(comp) {
		t.insert_equal(first, last);
	}

	multiset(const multiset<Key, Compare, Alloc>& x) :t(x.t) { }
	multiset<Key, Compare, Alloc>& operator=(const multiset<Key, Compare, Alloc>& x) {
		t = x.t;
		return *this;
	}

	//元素操作
	key_compare key_comp() const {
		return t.key_comp();
	}

	value_compare value_comp() const {
		return t.key_comp();
	}

	iterator begin() const {
		return t.begin();
	}

	iterator end() const {
		return t.end();
	}

	reverse_iterator rbegin() const {
		return t.rbegin();
	}

	reverse_iterator rend() const {
		return t.rend();
	}

	bool empty() const {
		return t.empty();
	}

	size_type size() const {
		return t.size();
	}

	size_type max_size() const {
		return t.max_size();
	}

	void swap(set<Key, Compare, Alloc>& x) {
		t.swap(x.t);
	}

	//insert/以及erase操作
	typedef pair<iterator, bool> pair_iterator_bool;
	pair<iterator, bool> insert(const value_type& x) {
		pair<typename rep_type::iterator, bool> p = t.insert_equal(x);
		return pair<iterator, bool>(p.first, p.second);
	}

	iterator insert(iterator position, const value_type& x) {
		typedef typename rep_type::iterator rep_iterator;
		return t.insert_equal((rep_iterator&)position, x);
	}

	template<class InputIterator>
	void insert(InputIterator first, InputIterator last) {
		t.insert_equal(first, last);
	}

	void erase(iterator position) {
		typedef typename rep_type::iterator rep_iterator;
		t.erase((rep_iterator&)position);
	}

	size_type erase(const key_type& x) {
		return t.erase(x);
	}

	void erase(iterator first, iterator last) {
		typedef typename rep_type::iterator rep_iterator;
		t.erase((rep_iterator&)first, (rep_iterator&)last);
	}

	void clear() {
		t.clear();
	}

	//set operations
	iterator find(const key_type& x) const {
		return t.find(x);
	}

	size_type count(const key_type& x) const {
		return t.size(x);
	}

	iterator lower_bound(const key_type& x) const {
		return t.lower_bound(x);
	}

	iterator upper_bound(const key_type& x) const {
		return t.upper_bound(x);
	}

	pair<iterator, iterator> equal_range(const key_type& x) const {
		return t.equal_range_multi(x);
	}

	friend bool operator==(const multiset& lhs, const multiset& rhs) { return lhs.t == rhs.t; }
	friend bool operator< (const multiset& lhs, const multiset& rhs) { return lhs.t < rhs.t; }
};
// 重载比较操作符
template <class Key, class Compare, class Alloc>
bool operator==(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
	return lhs == rhs;
}

template <class Key, class Compare, class Alloc>
bool operator<(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
	return lhs < rhs;
}

template <class Key, class Compare, class Alloc>
bool operator!=(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
	return !(lhs == rhs);
}

template <class Key, class Compare, class Alloc>
bool operator>(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
	return rhs < lhs;
}

template <class Key, class Compare, class Alloc>
bool operator<=(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
	return !(rhs < lhs);
}

template <class Key, class Compare, class Alloc>
bool operator>=(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
	return !(lhs < rhs);
}

3.2 map容器/multimap容器
map容器稍微有所不同,map中的所有元素都是pair,同时拥有实值和键值。我们不可以随意修改map的键值,因为这样会破坏map容器的排序规则,但是可以随意其实值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值