STL笔记之RBtree

红黑树(RBtree)不仅是一个二叉搜索树,而且必须满足以下规则:

  1. 每个节点不是红色就是黑色;
  2. 根节点为黑色;
  3. 如果节点是红色,其子节点必为黑色;
  4. 任一节点之NULL(树尾端)的任何路径,所含之黑节点必须相同。

根据规则4可知,新增节点必须为红;根据规则3可知,新增节点之父节点必须为黑,当新节点根据二叉搜索树规则到达其插入点,却未能符合上述规则时,就必须调整颜色并旋转树形。

节点设计

typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;

struct __rb_tree_node_base
{
	typedef __rb_tree_color_type color_type;
	typedef __rb_tree_node_base* base_ptr;

	color_type color;//节点颜色,非红即黑
	base_ptr parent;//rb树许多操作需要知道父节点
	base_ptr left;//指向左节点
	base_ptr right;//指向右节点

	static base_ptr minium(base_ptr x)
	{
		while (x->left != 0)
			x = x->left;
		return x;
	}

	static base_ptr maximum(base_ptr x)
	{
		while (x->right !=0 )
			x = x->right;
		return x;
	}
};

template<class Value>
struct __rb_tree_node:public __rb_tree_node_base
{
	typedef __rb_tree_node<Value>* link_type;
	Value value_field;//节点值
};

RBtree的迭代器

RBtree的迭代器的加减操作有点像中序遍历,operator++获得后一个节点(比它大的节点中最小的那个),operator--获得前一个节点(比它小的节点中最大的那个)。

header节点:header节点为红色节点,为end(),其左子节点为最左节点(most left,即最小值)begin(),右子节点为最右节点(most right,即最大值),其父节点为根节点(root())。根节点的父节点为header节点。

struct __rb_tree_base_iterator
{
	typedef __rb_tree_node_base::base_ptr base_ptr;
	typedef bidirectional_iterator_tag iterator_category;
	typedef ptrdiff_t difference_type;

	base_ptr node;//用来与容器之间产生一个连结关系

	//以下其实可实现于operator++内,因再无他处会调用此函数
	void increment()
	{
		if (node->right != 0)
		{
			//如果有右子节点就向右走,然后一直沿左子树走到底,即为解答
			node = node->right;
			while (node->left != 0)
				node = node->right;
		}
		else {
			//如果没有右子节点
			base_ptr y = node->parent;//找出父节点
			while (node == y->right) {//如果现行节点本身是个右子节点
				node = y;//就一直上溯,知道不为右子节点为止
				y = y->parent;
			}
			if (node->right != y)//若此时的右子节点不等于此时的父节点
				node = y;//此时的父节点即为解答
		}
		//以上判断“若此时的右子节点不等于此时的父节点”,是为了应付一种
		//特殊情况:我们要寻找根节点的下一节点,而恰巧根节点无右子节点,即根节点为最大值
		//当然,以上特殊做法必须配合RBtree根节点与特殊header之间打特殊关系
	}


	//以下其实可实现于operator--,因再无他处会调用此函数
	void decrement()
	{
		if (node->color == __rb_tree_red&&//如果是红节点且
			node->parent->parent == node)//父节点的父节点等于自己
			node = node->right;//右子节点即为解答
		//以上情况发生于node为header时(亦即node为end()时)
		//注意,header之右子节点即mostright,指向整棵树的max节点
		else if (node->left != 0) {
			//如果有左子节点,令y指向左子节点
			//当y有右子节点时,一直往右子节点走到底
			//最后即为答案
			base_ptr y = node->left;
			while (y->right != 0)
				y = y->right;
			node = y;
		}
		else {
			//既非根节点,亦无左子节点
			//找出父节点
			//当现行节点身为左子节点时
			//一直交替往上走,直到现行节点不为左子节点
			base_ptr y = node->parent;
			while (node == y->left) {
				node = y;
				y = y->parent;
			}
			node = y;//此时的父节点即为答案
		}
	}
};

特殊情况:

  1. begin()节点(most left)自减
    begin()不为根节点时,获得end()即header;
    begin()为根节点时,获得begin()。
  2. end()节点(即header节点)自减
    获得most right。
  3. most right自加
    不为根节点时,获得end()即header;
    为根节点时,获得end()即header。
//RBtree的正规迭代器
template<class Value,class Ref,class Ptr>
struct __rb_tree_iterator:public __rb_tree_base_iterator
{
	typedef Value value_type;
	typedef Ref reference;
	typedef Ptr pointer;
	typedef __rb_tree_iterator<Value, Value&, Value*> iterator;
	typedef __rb_tree_iterator<Value, const Value&, const Value*> const_iterator;
	typedef __rb_tree_iterator<Value, Ref, Ptr> self;
	typedef __rb_tree_iterator<Value>* link_type;

	__rb_tree_iterator(){}
	__rb_tree_iterator(link_type x) { node = x; }
	__rb_tree_iterator(const iterator& it) { node = it.node; }

	reference operator*()const { return link_type(node)->value_field; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
	pointer operator->()const { return &(operator*()); }
#endif /*__SGI_STL_NO_ARROW_OPERATOR*/
	
	self& operator++() { increment(); return *this; }
	self operator++(int) {
		self tmp = *this;
		increment();
		return tmp;
	}

	self& operator--() { decrement(); return *this; }
	self operator--(int) {
		self tmp = *this;
		decrement();
		return tmp;
	}
};

数据结构

template<class Key,class Value,class KeyOfValue,class Compare,class Alloc=alloc>
class rb_tree {
protected:
	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;
protected:
	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(); }
	void put_node(link_type p) { rb_tree_node_allocator::deallocate(p); }

	link_type create_node(const value_type& x) {
		link_type tmp = get_node();//配置空间
		__STL_TRY{
			construct(&tmp->value_field,x);//构造内容
		}
		__STL_UNWIND(put_node(tmp));
		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:
	//RBtree只以三笔数据表现
	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 const Key& key(link_type x)
	{
		return KeyOfValue()(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 const Key& key(base_ptr x)
	{
		return KeyOfValue()(value(link_type(x)));
	}
	static color_type& color(link_type x)
	{
		return (color_type&)(link_type(x)->color);
	}

	//求取极大值和极小值,node class有实现此功能,交给它们即可
	static link_type minimum(link_type x) {
		return (link_type)__rb_tree_node_base::minium(x);
	}
	static link_type maximum(link_type x) {
		return (link_type)__rb_tree_node_base::maximum(x);
	}

public:
	typedef __rb_tree_iterator<value_type, reference, pointer> iterator;

private:
	iterator __insert(base_ptr x, base_ptr y, const value_type& v);
	link_type __copy(link_type x, link_type p);
	void __erase(link_type x);
	void init() {
		header = get_node();//产生一个节点空间,令header指向它
		color(header) = __rb_tree_red;//令header为红色,用来区分header和root
		rooot() = 0;
		leftmost() = header;//令header的左子节点为自己
		rightmost() = header;//令header的右子节点为自己
	}

public:
	rb_tree(const Compare& comp=Compare()):
		node_count(0), key_compare(comp) {
		init();
	}
	~rb_tree() {
		clear();
		put_node(header);
	}
	rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&
		operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x);

public:
	Compare key_comp()const { return key_compare; }
	iterator begin() { return leftmost(); }
	iterator end() { return header; }
	bool empty()const { return node_count == 0; }
	size_type size()const { return node_count; }
	size_type max_size()const { return size_type(-1); }

public:
	//将x插入到RBtree中,不允许节点重复
	pair<iterator, bool>insert_unique(const value_type& x);
	//将x插入到RBtree中,允许节点重复
	iterator insert_equal(const value_type& x);
//...
};

构造与内存管理

RBtree所定义的专属空间配置器rb_tree_node_allocator,每次可恰恰配置一个节点,使用simple_alloc<>。

RBtree的构造方式有两种,一种是以现有的RBtree复制一个新的RBtree,另一种是产生一棵空树。

元素操作

注意,虽然只指定实值,但RBtree一开始就要求用户明确设定所谓的KeyOfValue仿函数,因此,从实值(value)中取出键值(key)是毫无问题的。

插入操作:

扫描二维码关注公众号,回复: 2398376 查看本文章
//插入新值,节点键值允许重复
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& 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);
		//以上,遇大往左,遇小于或等于往右
	}
	return __insert(x, y, v);
	//以上,x为新值插入点,y为插入点之父节点,v为新值
};

//插入新值,节点键值不允许重复
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& v)
{
	link_type y = header;
	link_type x = root();
	bool comp = true;
	while (x != 0)
	{
		y = x;
		comp = key_compare(KeyOfValue()(v), key(x));//v键值小于目前节点键值?
		x = comp ? left(x) : right(x);//遇大则往左,遇小于或等于则往右
	}
	//离开while循环后,y所指即插入点之父节点(此时的它必为叶节点)

	iterator j = iterator(y);//令迭代器j指向插入点之父节点y
	if (comp)//如果离开while循环时comp为真,表示遇大,将插入左侧
		if (j == begin())//如果插入点之父节点为最左节点
			return pair<iterator, bool>(__insert(x, y, v), true);
	//以上x为插入点,y为插入点之父节点,v为新值
		else
			--j;//调整j,回头准备测试
	if (key_compare(key(j.node), KeyOfValue()(v)))
		//新键值不与既有节点之键值重复
		return pair<iterator, bool>(__insert(x, y, v), true);
	//以上x为插入点,y为插入点之父节点,v为新值

	//至此,表示新值一定与树中键值重复,那么就不该插入新值
	return pair<iterator, bool>(j, false);
};


//实际插入执行程序
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& v)
//x_为新值插入点,y_为插入点之父节点,v为新值
{
	link_type x = (link_type)x_;
	link_type y = (link_type)y_;
	link_type z;

	//key_compare是键值大小比较准则
	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())
			leftmost() = z;
	}
	else {
		z = create_node(v);//产生一个新节点
		right(y) = z;//令新节点成为插入点之父节点y的右子节点
		if (y == rightmost())
			rightmost() = z;//维护rightmost(),使它永远指向最右节点
	}
	parent(z) = y;//设定新节点的父节点
	left(z) = 0;//设定新节点的左子节点
	right(z) = 0;//设定新节点的右子节点
	//新节点的颜色将在__rb_tree_rebalance()中设定并调整
	//参数1为新增节点,参数2为root
	__rb_tree_rebalance(z, header->parent);
	++node_count;//节点数累加
	return iterator(z);//返回一个迭代器,指向新增节点
}

调整RBtree

任何插入操作后,于节点插入完毕后,都要做一次调整操作,将树的状态调整到RBtree的要求。

//全局函数
//重新令树形平衡
//参数1为新增节点,参数2为root
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;//令y为伯父节点
			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;//令y为伯父节点
			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;//根节点永远为黑
}

//全局函数
//新节点必为红节点,如果插入处之父节点亦为红节点,就违反红黑树规则
//需要做树形旋转及颜色改变
inline void
__rb_tree_rotate_left(__rb_tree_node_base* x,
	__rb_tree_node_base*& root)
{
	//x为旋转点
	__rb_tree_node_base* y = x->right;//令y为旋转点的右子节点
	x->right = y->left;
	if (y->left != 0)
		y->left->parent = x;//设定父节点
	y->parent = x->parent;

	//令y完全顶替x的地位
	//必须将x对其父节点的关系完全接受过来
	if (x == root)//x为根节点
		root = y;
	else if (x == x->parent->left)//x为其父节点的左子节点
		x->parent->left = y;
	else
		x->parent->right = y;//x为其父节点的右子节点
	y->left = x;
	x->parent = y;
}


//全局函数
//新节点必为红节点,如果插入处之父节点亦为红节点,就违反红黑树规则
//需要做树形旋转及颜色改变
inline void
__rb_tree_rotate_right(__rb_tree_node_base* x,
	__rb_tree_node_base*& root)
{
	//x为旋转点
	__rb_tree_node_base* y = x->left;//令y为旋转点的左子节点
	x->left = y->right;
	if (y->right != 0)
		y->right->parent = x;//设定父节点
	y->parent = x->parent;

	//令y完全顶替x的地位
	//必须将x对其父节点的关系完全接受过来
	if (x == root)//x为根节点
		root = y;
	else if (x == x->parent->right)//x为其父节点的右子节点
		x->parent->right = y;
	else
		x->parent->left = y;//x为其父节点的左子节点
	y->right = x;
	x->parent = y;
}

元素的搜寻

find函数:

//寻找RB树中是否有键值为k的节点
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>::
find(const Value& k)
{
	link_type y = header;
	link_type x = root();

	while (x != 0) {
		if (key_compare(key(x), k))
			y = x, x = left(x);
		else
			x = right(x);

		iterator i = iterator(y);
		return (j == end() || key_compare(k, key(j.node))) ? end() : j;
	}
}


猜你喜欢

转载自blog.csdn.net/s_hit/article/details/79528433