紅黑樹--(上)

    紅黑樹是應用的最多的二叉樹之一,包括STL中的map和set,以及Linux的內核等等都使用到了紅黑樹。今天花了一下午的時間實現了紅黑樹的一些功能,主要是插入節點的情況分析(刪除節點還在研究)。

    首先紅黑樹的性質比較重要,這裏就簡單的說一下吧!

     性質1. 節點是紅色或黑色。

     性質2. 根節點是黑色。

     性質3. 每個葉節點是黑色的。

     性質4. 每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)

     性質5. 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。

   其中最重要的是最後兩條,它的特性體現在這兩條規則上,記住這兩條規則後你就能比較清楚的理解紅黑樹了。

   我設計的紅黑樹的節點的形式如下:

template<class K,class V>
struct RedBlackTreeNode
{
	K			  _key;     //鍵
	V			  _val;	    //值
	Color			  _color;   //顏色
	RedBlackTreeNode<K, V>*   _parent;  //父節點 
	RedBlackTreeNode<K, V>*   _left;    //左子節點 
	RedBlackTreeNode<K, V>*   _right;   //右子節點
	
	RedBlackTreeNode(const K& key, const V& val)
		: _key(key)
		, _val(val)
		, _color(Red)
		, _parent(NULL)
		, _left(NULL)
		, _right(NULL)
	{}
};
下面我就分析一下紅黑樹插入節點時候的情況。






常見的情況有上述幾種,不過我這裏只畫出了一半(左半邊),右半邊和左半邊對稱,相信憑大家的能力,這點東西算不了什麼,所以我們大概只需要考慮這幾種情況就行了,在實現的時候將右半邊加上就好了,下面我就給出代碼,參考一下:

#pragma once

#include <iostream>
using namespace std;

enum Color
{
	Red,
	Black
};

template<class K,class V>
struct RedBlackTreeNode
{
	K			  _key;      //鍵
	V			  _val;	     //值
	Color			  _color;    //顏色
	RedBlackTreeNode<K, V>*   _parent;   //父節點 
	RedBlackTreeNode<K, V>*   _left;     //左子節點 
	RedBlackTreeNode<K, V>*   _right;    //右子節點
	
	RedBlackTreeNode(const K& key, const V& val)
		: _key(key)
		, _val(val)
		, _color(Red)
		, _parent(NULL)
		, _left(NULL)
		, _right(NULL)
	{}
};

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

	void InOrder()
	{
		_InOrder(_root);
	}
	
	Node* Find(const K &key)
	{
		Node *cur = _root;
		while (cur)
		{
			if (cur->_key == key)
			{
				return cur;
			}
			else if(key < cur->_key)
			{
				cur = cur->_left
			}
			else
			{
				cur = cur->_right;
			}
		}
		return cur;
	}

	bool Insert(const K &key, const V &val)
	{
		if (_root == NULL)
		{
			_root = new Node(key, val);
			_root->_color = Black;
			return true;
		}

		//找插入點
		Node *parent = NULL;
		Node *cur = _root;
		while (cur)
		{
			parent = cur;
			if (cur->_key == key)
				return false;
			else if (cur->_key < key)
				cur = cur->_right;
			else
				cur = cur->_left;
		}

		//連接節點
		cur = new Node(key, val);
		cur->_parent = parent;
		if (parent->_key > key)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}

		//根據紅黑樹條件調節
		while (parent != _root && parent->_color == Red) //祖父節點存在且父節點爲紅色
		{
			Node* grandfa = parent->_parent;
			if (grandfa->_left == parent)
			{ //新插入節點位於grandfa的左子樹
				Node *uncle = grandfa->_right;
				if (uncle && uncle->_color == Red)
				{
					grandfa->_color = Red;
					parent->_color = Black;
					uncle->_color = Black;
					
					cur = grandfa;
					if (cur == _root)
					{//遍歷到根了
						break;
					}
					parent = cur->_parent;
					//continue;
				}
				else
				{
					if (cur == parent->_right)
					{//左單旋
						_RotateL(parent);
						cur = cur->_left;
						parent = cur->_parent;
					}
					//右單旋
					_RotateR(grandfa);
					parent->_color = Black;
					parent->_left->_color = Red;
					parent->_right->_color = Red;
					break;
				}
			}
			else
			{ //新插入節點位於grandfa的右子樹
				Node *uncle = grandfa->_left;
				if (uncle && uncle->_color == Red)
				{
					grandfa->_color = Red;
					parent->_color = Black;
					uncle->_color = Black;

					cur = grandfa;
					if (cur == _root)
					{
						break;
					}
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_left)
					{ //右單旋
						_RotateR(parent);
						cur = cur->_right;
						parent = cur->_parent;
					}
					//左單旋
					_RotateL(grandfa);
					parent->_color = Black;
					parent->_left->_color = Red;
					parent->_right->_color = Red;
					break;
				}
			}
		}
		_root->_color = Black;
		return true;
	}


	bool Remove(const K &key)
	{
		Node* pos = Find(key);
		if (pos == NULL)
		{
			return false;
		}
		/*
			未完成
		*/
		return true;
	}

	bool IsRight()
	{	
		//統計一條路徑上的黑色節點的個數
		Node *cur = _root;
		int blacknum = 0;
		while (cur)
		{
			if (cur->_color == Black)
				++blacknum;
			cur = cur->_left;
		}

		return _CheckRBTree(_root,blacknum,0);
	}

	~RedBlackTree()
	{}

protected:
	bool _CheckRBTree(Node *root,int blacknum,int curblacknum)
	{
		if (root == NULL)
			return true;

		if (root->_color == Black)
		{//黑色節點
			++curblacknum;
		}
		else
		{//紅色節點
			if (root->_parent && root->_parent->_color == Red)
			{//不合要求
				cout << "連續兩個紅色節點" << endl;
				return false;
			}
		}

		if (root->_left == NULL && root->_right == NULL)
		{//葉子結點
			if (curblacknum == blacknum)
				return true;

			return false;
		}

		return _CheckRBTree(root->_left,blacknum,curblacknum) 
			&& _CheckRBTree(root->_right,blacknum,curblacknum);
	}

	void _InOrder(Node *root)
	{
		if (root)
		{
			_InOrder(root->_left);
			cout << "[" << root->_key << "," << root->_val << "] ";
			_InOrder(root->_right);
		}
	}

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

		if (subRL)
		{ //如果存在
			subRL->_parent = parent;
		}
		subR->_parent = parent->_parent;		
		parent->_parent = subR;
		subR->_left = parent;
		parent->_right = subRL;
		parent = subR;
		if (parent->_parent)
		{
			Node* grandfa = parent->_parent;
			if (grandfa->_key > parent->_key)			
				grandfa->_left = parent;			
			else			
				grandfa->_right = parent;
		}
		else
		{
			_root = parent;
		}
	}
	
	void _RotateR(Node *&parent)
	{ //右單旋
		Node* subL = parent->_left;
		Node *subLR = subL->_right;

		if (subLR)
		{
			subLR->_parent = parent;
		}
		subL->_parent = parent->_parent;
		parent->_parent = subL;
		subL->_right = parent;
		parent->_left = subLR;
		parent = subL;
		if (parent->_parent)
		{
			Node *grandfa = parent->_parent;
			if (grandfa->_key > parent->_key)
				grandfa->_left = parent;
			else
				grandfa->_right = parent;
		}
		else
		{
			_root = parent;
		}
	}

protected:
	Node	*_root;
};

void TestRedBlackTree()
{
	RedBlackTree<int, int> rb;
	rb.Insert(3, 1);
	rb.Insert(2, 1);
	rb.Insert(1, 1);
	rb.Insert(5, 1);
	rb.Insert(8, 1);
	rb.Insert(6, 1);
	rb.Insert(7, 1);
	rb.InOrder();
	cout <<endl<< "isRBTree ? " << rb.IsRight() << endl;
}
      這裏我主要是實現的是紅黑樹的插入功能,以及中序遍歷,以及檢查紅黑樹是否正確,紅黑樹的刪除還待研究一下,下次補充上來,大家對於上面的過程有什麼問題可以給我留言,若是還有不足的地方也歡迎大家指出。

發佈了194 篇原創文章 · 獲贊 88 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章