数据结构之红黑树

         一直觉得数据结构中最难以搞懂的结构之一就是红黑树了。所以一开始就对红黑树有一股“敬畏感”,所以在学习红黑树的时候在网上查找了很多资料。但是网上的资料在讲解时条理不清,有的只是点甚至一笔带过,树的变化也没有体现出来。自己总结了好久才把它给搞定,再此,向大家分享一下个人的思路。


      首先,我们要知道红黑树的规则

  性质1. 节点是红色或黑色。

  性质2. 根是黑色。

  性质3. 所有叶子都是黑色(叶子是NIL节点)。

  性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

  性质5. 从任一节点到其每个叶子的所有简单路径 都包含相同数目的黑色节点。


  咋一看红黑树的规则很多,要想所有节点都满足这5条性质还是有难度的,但是其实这5条性质是相互依赖的,只要我们掌握一些方法去调整子树,整棵树将会满足这些性质(在这里不得不感叹前辈们的智慧真的是相当的牛)。


在这里博主主要讨论的是红黑树的插入操作

       红黑树的插入节点是不难的,它的插入操作类似于二叉搜索树,在这里就略过了,但是有一点要说明,每个新插入的结点默认都是红色的,所以只要心插入的结点的父节点是黑色,那么我们就无需调整树结构,红黑树并不是AVL平衡二叉树那么的严格。这也是红黑树应用广泛的原因。

总结起来新插入节点可以分为以下几种情况:(cur为新插入的结点,root为根节点,parent为cur的父节点,uncle为parent的兄弟结点,grandpa为parent的父节点

1.root为空

   将新结点给root,并将结点改为黑色(性质2)。

2.parent的颜色为黑色

   直接插入cur(直接就满足所有条件)

3.parent的颜色为红色

       此情况下有可以分为以下几种情况:

           1.cur为红,parent为红,grandpa为黑,uncle存在且为红

                       调整颜色:grandpa为红,uncle为黑,parent为黑(注意不管是何种情况,cur的颜色一致不变,为红

            2.cur为红,parent为红,grandpa为黑,uncle不存在或者为黑

                      调整树和结点颜色:(一)grandpa->left==parent    parent->left==cur。

                                                                        右旋转,parent为黑,grandpa为红,cur为红

                                                            (二)grandpa->right==parent    parent->right=cur。

                                                                        左旋转,parent为黑,grandpa为红

                                                               (三)grandpa->_left == parent,parent->_right == cur

                                                                           左右双旋,cur为黑,grandpa为红

                                                                 (四)grandpa->right == parent,parent->left == cur

                                                                          右左双旋,cur为黑,grandpa为红


<span style="font-size:14px;">#pragma once
#include<iostream>

using namespace std;


enum Color
{
	RED,
	BLACK
};

template<class K,class V>
struct RBNode
{
	RBNode<K, V>* _left;
	RBNode<K, V>* _right;
	RBNode<K, V>* _parent;
	K _key;
	V _value;
	Color _color;
	RBNode(const K& key, const V& value)
		:_left(NULL)
		, _right(NULL)
		, _parent(NULL)
		, _key(key)
		, _value(value)
		, _color(RED)
	{}
};

template<class K,class V>
class RBTree
{
public:
	typedef RBNode<K, V> Node;
	RBTree()
		:_root(NULL)
	{}
	bool Insert(const K& key, const V& value)
	{
		if (_root == NULL)
		{
			_root = new Node(key, value);
			_root->_color = BLACK;
			return true;
		}
		Node* cur = _root;
		Node* parent = NULL;
		while (cur)
		{
			parent = cur;
			if (cur->_key > key)
				cur = cur->_left;
			else if (cur->_key < key)
				cur = cur->_right;
			else
				return false;
		}
		cur = new Node(key, value);
		cur->_parent = parent;
		if (parent->_key > key)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		if (parent->_color == BLACK)//如果插入的结点的父节点是黑色,那么不必调整
			return true;
		while (cur != _root &&cur->_color == RED&& parent->_color == RED)//只有当parent为红,cur为红时调整,cur!=root保证parent不为空
		{
			Node* grandpa = parent->_parent;
			Node* uncle = NULL;
			if (parent == grandpa->_left)
				uncle = grandpa->_right;
			else
				uncle = grandpa->_left;
			if (uncle&&uncle->_color == RED)
			{
				grandpa->_color = RED;
				uncle->_color = BLACK;
				parent->_color = BLACK;
			}
			else
			{
				if (grandpa->_left == parent&&parent->_left == cur)
				{
					_RotateR(grandpa);
					grandpa->_color = RED;
					parent->_color = BLACK;
					cur->_color = RED;
				}
				if (grandpa->_right == parent&&parent->_right == cur)
				{
					_RotateL(grandpa);
					parent->_color = BLACK;
					grandpa->_color = RED;
				}
				if (grandpa->_left == parent&&parent->_right == cur)
				{
					_RotateLR(grandpa);
					cur->_color = BLACK;
					grandpa->_color = RED;
				}
				if (grandpa->_right == parent&&parent->_left == cur)
				{
					_RotateRL(grandpa);
					cur->_color = BLACK;
					grandpa->_color = RED;

				}
			}
			_root->_color = BLACK;//每次调整完树都要把根置为黑色(性质2)
			cur = parent;
			parent = cur->_parent;
		}
		_root->_color = BLACK;
		return true;
	}</span><pre name="code" class="cpp"><span style="font-size:14px;">protected:

	void _RotateR(Node*& parent)//右旋转
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* pNode = parent->_parent;
		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent = parent;
		}
		subL->_right = parent;
		parent->_parent = subL;
		parent = subL;
		subL->_parent = pNode;
		
		if (pNode == NULL)
		{
			_root = subL;
		}
		else
		{
			if (pNode->_key > subL->_key)
			{
				pNode->_left = subL;
			}
			else
			{
				pNode->_right = subL;
			}
		}
	}
	void _RotateL(Node*& parent)//左旋转
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* pNode = parent->_parent;
		parent->_right = subRL;
		if (subRL)
		{
			subRL->_parent = parent;
		}
		subR->_left = parent;
		parent->_parent = subR;

		parent = subR;
		parent->_parent = pNode;

		if (pNode == NULL)
		{
			_root = subR;
		}
		else
		{
			if (pNode->_key > subR->_key)
			{
				pNode->_left = subR;
			}
			else
			{
				pNode->_right = subR;
			}
		}
	}
	void _RotateRL(Node* parent)//右左双旋
	{
		_RotateR(parent->_right);
		_RotateL(parent);
	}
	void _RotateLR(Node* parent)//左右双旋
	{
		_RotateL(parent->_left);
		_RotateR(parent);
	}

protected:
	Node* _root;
};</span>


          
    博主还在研究红黑树的增删改的实现,水平有限,如有错误请多指正!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值