红黑树的实现

红黑树(RBT)的定义它或者是一颗空树,或者是具有一下性质的二叉查找树:

1.节点非红即黑。

2.根节点是黑色。

3.所有NULL结点称为叶子节点,且认为颜色为黑

4.所有红节点的子节点都为黑色。

5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。

                                                             

上面的定义理解起来有点费解,所以我总结了以下三点,只要满足以下三点就可以是红黑树了。

                                       1.根节点必须是黑树

                               2.红树不能连续链接,黑树可以。

                               3.每条路径上黑树的个数必须是相同的。

插入操作(Insert)

由于性质的约束:插入点不能为黑节点,应插入红节点。因为你插入黑节点将破坏性质5,所以每次插入的点都是红结点,但是若他的父节点也为红,那就会破坏了性质4,所以要做一些“旋转”和一些节点的变色!另外为叙述方便,我们给要插入的节点分别定义如下:

             N(红色),父节点为P,祖父节点为G,叔节点为U

下边将一一列出所有插入时遇到的情况:

情况一:该树为空树,直接插入根结点的位置,违反性质1,把节点颜色有红改为黑即可

情况二:插入节点N的父节点P为黑色,不违反任何性质,无需做任何修改。

情况三:N为红,P为红,(祖节点一定存在,且为黑,下边同理)U也为红,这里不论P是G的左孩子,还是右孩子;不论N是P的左孩子,还是右孩子如下图所示:

操作:先把P和U变为黑色,然后G变为红色

                                                                                                                                                                      


情况四:N为红,P为红,U为黑,P为G的左孩子,N为P的左孩子(或者P为G的右孩子,N为P的左孩子;反正就是同向的)如下图所示:

操作:将P变黑,G变红,然后以p为轴右旋

                                                                                                                                                          

情况五:N为红,P为红,U为黑,P为G的左孩子,N为P的右孩子(或者P为G的右孩子,N为P的左孩子;反正两方向相反)。如下图所示:

 操作:首先以P为轴左旋,然后将p和N指向的地址交换,然后就转换为情况四                                    

                                                                                                                                                                                 


代码如下:


数据结构定义如下:

enum Colour
{
	RED,
	BLACK,
};

template<class K, class V>
struct RBTreeNode
{
	// 链接结构
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;

	// Key/Value
	K _key;
	V _value;

	// 颜色
	Colour _col;

	RBTreeNode(const K& key, const V& value, Colour col = RED)
		:_left(NULL)
		, _right(NULL)
		, _parent(NULL)
		, _col(col)
		, _key(key)
		, _value(value)

	{}
};
操作代码如下:

template<class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	RBTree()
		:_root(NULL)
	{}

	bool Insert(const K& key, const V& value)
	{
		//1.树为空
		if (_root == NULL)
		{
			_root = new Node(key, value, BLACK);
			return true;
		}

		// 查找位置,插入节点
		Node* parent = NULL;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(key, value, RED);
		if (parent->_key < key)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}

		// 调整
		while (cur != _root && parent->_col == RED)   //这两个条件说明了cur一定存在parent 和 grandfather
		{
			Node* grandfather = parent->_parent;
			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;

				// case1
				if (uncle && uncle->_col == RED)   //uncle存在且uncle的颜色为红色
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else // case2/case3    //uncle不存在 或 uncle存在但颜色为黑色
				{
					// case3->case2
					if (cur == parent->_right)
					{
						_RotateL(parent);    //先左旋在交换
						swap(cur, parent);     //交换cur和parent的地址,此时cur指向parent的地址,parent指向cur的地址
					}

					grandfather->_col = RED;
					parent->_col = BLACK;

					_RotateR(grandfather);    //在右旋
				}
			}
			else   //parent == grandfather->_right
			{
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_left)
					{
						_RotateR(parent);
						swap(cur, parent);
					}

					grandfather->_col = RED;
					parent->_col = BLACK;

					_RotateL(grandfather);
				}
			}
		}

		_root->_col = BLACK;

		return true;
	}

	void _RotateL(Node* parent)		//左旋转
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;		//修改指针(1)
		if (subRL)
			subRL->_parent = parent;

		subR->_left = parent;	    //修改指针(2)
		subR->_parent = parent->_parent;
		parent->_parent = subR;

		if (subR->_parent == NULL)
		{
			_root = subR;
		}
		else
		{
			if (subR->_parent->_key > subR->_key)
			{
				subR->_parent->_left = subR;	//修改指针(3)
			}
			else
			{
				subR->_parent->_right = subR;
			}
		}
	}

	void _RotateR(Node* parent)    //右旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent = parent;
		}

		subL->_right = parent;
		subL->_parent = parent->_parent;
		parent->_parent = subL;

		if (subL->_parent == NULL)
		{
			_root = subL;
		}
		else
		{
			if (subL->_parent->_key > subL->_key)
			{
				subL->_parent->_left = subL;
			}
			else
			{
				subL->_parent->_right = subL;
			}
		}
	}

	void InOrder()
	{
		return _InOrder(_root);
	}

	void _InOrder(Node* root)
	{
		if (root == NULL)
		{
			return;
		}

		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}


protected:
	Node* _root;
};

以上仅是红黑树的插入操作和打印操作,希望以上代码能帮助到想学编程的童鞋。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值