C++ RBTree 紅黑樹的實現

紅黑樹的性質

  1. 每個結點不是紅色就是黑色
  2. 根節點是黑色的
  3. 如果一個根節點是紅色的,則它的兩個葉子結點是黑色的(沒有兩個連續的紅色結點)
  4. 對於每個結點,從該結點到其所有後代葉結點的簡單路徑上,均包含相同數目的黑色結點(每條路徑上黑色結點的數量相等)
  5. 所有葉子結點爲黑(與平時不同,這裏的葉子結點是指空的葉子結點,即爲NULL)

紅黑樹是一種特殊的二叉查找樹,這意味着它滿足二叉查找樹的特徵:任意一個節點所包含的鍵值,大於等於左孩子的鍵值,小於等於右孩子的鍵值。(相較於二叉查找樹,我們只要對結點的顏色進行判斷和調整)。
紅黑樹雖然複雜,但它的最壞情況運行時間也是非常良好的,它可以在O(log n)時間內做查找,插入和刪除(n是樹中結點樹)。

紅黑樹結點

//RBTNode.h
enum RBTColor { Black, Red };

template<class KeyType>
struct  RBTNode
{
	KeyType key;
	RBTColor color;
	RBTNode<KeyType> * left;
	RBTNode<KeyType> * right;
	RBTNode<KeyType> * parent;
	RBTNode(KeyType k, RBTColor c, RBTNode* p, RBTNode*l, RBTNode*r) :
		key(k), color(c), parent(p), left(l), right(r) { };
};

紅黑樹的實現

//RBTree.h
#include"RBTNode.h"
#include <iomanip>

template<class T>
class  RBTree
{
public:
	RBTree();
	~RBTree();

	void insert(T key);    //插入結點,key爲鍵值,外部接口
	void remove(T key); //刪除key的節點
	RBTNode<T>* search(T key);
	void print();
	void preOrder();    //前序遍歷 打印紅黑樹
	void inOrder();    //中序遍歷
	void postOrder();    //後序遍歷		
	


private:
	void leftRotate(RBTNode<T>* &root, RBTNode<T>* x);// 左旋
	void rightRotate(RBTNode<T>* &root, RBTNode<T>* y);// 右旋

	void insert(RBTNode<T>* &root, RBTNode<T>* node);// 插入結點,內部接口
	void InsertFixUp(RBTNode<T>* &root, RBTNode<T>* node);
	void destory(RBTNode<T>* &node);

	void remove(RBTNode<T>*& root, RBTNode<T>*node);//刪除爲KEY的結點
	void removeFixUp(RBTNode<T>* &root, RBTNode<T>* node, RBTNode<T>*parent);

	RBTNode<T>* search(RBTNode<T>*node, T key) const;
	void print(RBTNode<T>* node)const;
	void preOrder(RBTNode<T>* tree)const;
	void inOrder(RBTNode<T>* tree)const;
	void postOrder(RBTNode<T>* tree)const;
private:
	RBTNode<T>*root;
};

template<class T>		//構造函數
RBTree<T>::RBTree() :root(NULL) {
	root = nullptr;
}
template<class T>		//析構函數
RBTree<T>::~RBTree() {
	destory(root);
}
template<class T>		//左旋
void RBTree<T>::leftRotate(RBTNode<T>* &root, RBTNode<T>* x) {
	RBTNode<T>*y = x->right;
	x->right = y->left;
	if (y->left != NULL)
		y->left->parent = x;

	y->parent = x->parent;
	if (x->parent == NULL)
		root = y;
	else {
		if (x == x->parent->left)
			x->parent->left = y;
		else
			x->parent->right = y;
	}
	y->left = x;
	x->parent = y;
};
template<class T>		//右旋
void RBTree<T>::rightRotate(RBTNode<T>*&root, RBTNode<T>*y) {
	RBTNode<T>*x = y->left;
	y->left = x->right;
	if (x->right != NULL)
		x->right->parent = y;

	x->parent = y->parent;
	if (y->parent == NULL)
		root = x;
	else {
		if  (y == y->parent->right)
			y->parent->right = x;
		else
			y->parent->left = x;
	}
	x->right = y;
	y->parent = x;
};
template<class T>		//插入
void RBTree<T>::insert(T key)
{
	RBTNode<T>*z = new RBTNode<T>(key, Red, NULL, NULL, NULL);
	insert(root, z);
};
template<class T>
void RBTree<T>::insert(RBTNode<T>* &root, RBTNode<T>* node)
{
	RBTNode<T> *x = root;
	RBTNode<T> *y = NULL;
	while (x != NULL)
	{
		y = x;
		if (node->key > x->key)
			x = x->right;
		else
			x = x->left;
	}
	node->parent = y;
	if(y!=NULL)
	{
		if (node->key > y->key)
			y->right = node;
		else
			y->left = node;
	}
	else 
		root = node;
	node->color = Red;
	InsertFixUp(root, node);
};
template<class T>
void RBTree<T>::InsertFixUp(RBTNode<T>* &root, RBTNode<T>* node)
{
	RBTNode<T>*parent;
	parent = node->parent;
	while (node != RBTree::root  && parent->color == Red)
	{
		RBTNode<T>*gparent = parent->parent;
		if (gparent->left == parent)
		{
			RBTNode<T>*uncle = gparent->right;
			if (uncle != NULL && uncle->color == Red)
			{
				parent->color = Black;
				uncle->color = Black;
				gparent->color = Red;
				node = gparent;
				parent = node->parent;
			}
			else
			{
				if (parent->right == node)
				{
					leftRotate(root, parent);
					swap(node, parent);
				}
				rightRotate(root, gparent);
				gparent->color = Red;
				parent->color = Black;
				break;
			}
		}
		else
		{
			RBTNode<T>*uncle = gparent->left;
			if (uncle != NULL && uncle->color == Red)
			{
				gparent->color = Red;
				parent->color = Black;
				uncle->color = Black;

				node = gparent;
				parent = node->parent;
			}
			else
			{
				if (parent->left == node)
				{
					rightRotate(root, parent);
					swap(parent, node);
				}
				leftRotate(root, gparent);
				parent->color = Black;
				gparent->color = Red;
				break;
			}
		}
	}
	root->color = Black;
}
template<class T>
//銷燬紅黑樹
void RBTree<T>::destory(RBTNode<T>* &node) 
{
	if (node == NULL)
		return;
	destory(node->left);
	destory(node->right);
	delete node;
	node = nullptr;
}

template<class T>
void RBTree<T>::remove(T key) 
{
	RBTNode<T>*deletenode = search(root,key);
	if (deletenode != NULL)
		remove(root, deletenode);
}
template<class T>
void RBTree<T>::remove(RBTNode<T>*&root, RBTNode<T>*node)
{
	RBTNode<T> *child, *parent;
	RBTColor color;
	//被刪除節點左右結點都不爲空(不爲葉子結點)
	if (node->left != NULL && node->right != NULL)     
	{
		RBTNode<T> *replace = node;
		//找後繼結點(當前節點的右子樹的最下層的左結點)
		replace = node->right;
		while (replace->left != NULL)
		{
			replace = replace->left;
		}
		//被刪節點不爲根節點情況
		if (node->parent != NULL)
		{
			if (node->parent->left == node)
				node->parent->left = replace;
			else
				node->parent->right = replace;
		}
		//根節點情況
		else
			root = replace;
		//child是取代節點的右結點,是需要後續調整的結點
		//因爲replace是後繼結點,因此他不可能有左子節點
		//同理前驅結點不可能有右子節點
		child = replace->right;
		parent = replace->parent;
		color = replace->color;
		
		//被刪結點是取代結點(repalce)的父節點的情況
		if (parent == node)
			parent = replace;
		else
		{
			//child結點存在的情況
			if (child != NULL)
				child->parent = parent;
			parent->left = child;

			replace->right = node->right;
			node->right->parent = replace;
		}
		replace->parent = node->parent;
		replace->color = node->color;
		replace->left = node->left;
		node->left->parent = replace;
		if (color == Black)
			removeFixUp(root, child, parent);

		delete node;
		return;
	}
	//當被刪節點只有左(右)結點爲空情況,找出被刪結點的子節點
	if (node->left != NULL)    
		child = node->left;
	else
		child = node->right;

	parent = node->parent;
	color = node->color;
	if (child) 
	{
		child->parent = parent;
	}
	//被刪除節點不爲根節點
	if (parent)     
	{
		if (node == parent->left)
			parent->left = child;
		else
			parent->right = child;
	}
	//被刪除節點爲根節點
	else
		RBTree::root = child;		

	if (color == Black)
	{
		removeFixUp(root, child, parent);
	}
	delete node;

}
template<class T>
void RBTree<T>::removeFixUp(RBTNode<T>* &root, RBTNode<T>* node,RBTNode<T>*parent)
{
	RBTNode<T>*othernode;
	while ((!node) || node->color == Black && node != RBTree::root)
	{
		if (parent->left == node)
		{
			othernode = parent->right;
			if (othernode->color == Red)
			{
				othernode->color = Black;
				parent->color = Red;
				leftRotate(root, parent);
				othernode = parent->right;
			}
			else
			{
				if (!(othernode->right) || othernode->right->color == Black)
				{
					othernode->left->color=Black;
					othernode->color = Red;
					rightRotate(root, othernode);
					othernode = parent->right;
				}
				othernode->color = parent->color;
				parent->color = Black;
				othernode->right->color = Black;
				leftRotate(root, parent);
				node = root;
				break;
			}
		}
		else
		{
			othernode = parent->left;
			if (othernode->color == Red)
			{
				othernode->color = Black;
				parent->color = Red;
				rightRotate(root, parent);
				othernode = parent->left;
			}
			if ((!othernode->left || othernode->left->color == Black) && (!othernode->right || othernode->right->color == Black))
			{
				othernode->color = Red;
				node = parent;
				parent = node->parent;
			}
			else
			{
				if (!(othernode->left) || othernode->left->color == Black)
				{
					othernode->right->color = Black;
					othernode->color = Red;
					leftRotate(root, othernode);
					othernode = parent->left;
				}
				othernode->color = parent->color;
				parent->color = Black;
				othernode->left->color = Black;
				rightRotate(root, parent);
				node = root;
				break;
			}
		}
	}
	if (node)
		node->color = Black;
}

template<class T>
RBTNode<T>* RBTree<T>::search(T key) 
{
	return search(root, key);
}
template<class T>
RBTNode<T>* RBTree<T>::search(RBTNode<T>*node, T key) const
{
	if (node == NULL || node->key == key)
		return node;
	else
		if (key > node->key)
			return search(node->right, key);
		else
			return search(node->left, key);
}
template<class T>		//輸出二叉樹詳細信息
void RBTree<T>::print() {
	if (root == NULL)
		cout << "empty RBtree\n";
	else
		print(root);
}
template<class T>
void RBTree<T>::print(RBTNode<T>* node)const {
	if (node == NULL)
		return;
	if (node->parent == NULL)
		cout << node->key << "(" << node->color << ") is root" << endl;
	else if(node->parent->left==node)
	{
		cout << node->key << "(" << node->color << ") is "<<node->parent->key<<"'s "<<"left child" << endl;
	}
	else
	{
		cout << node->key << "(" << node->color << ") is " << node->parent->key << "'s " << "right child" << endl;
	}
	print(node->left);
	print(node->right);
}
template<class T>		//前序遍歷RB樹
void RBTree<T>::preOrder() {
	if (root == NULL)
		cout << "empty RBtree\n";
	else
		preOrder(root);
};
template<class T>		 
void RBTree<T>::preOrder(RBTNode<T>* tree)const {
		if (tree != NULL) {
			cout << tree->key << " ";
			preOrder(tree->left);
			preOrder(tree->right);
		}
	}
template<class T>		//中遍歷RB樹
void RBTree<T>::inOrder() {
	if (root == NULL)
		cout << "empty RBtree\n";
	else
		inOrder(root);
};
template<class T>		 
void RBTree<T>::inOrder(RBTNode<T>* tree)const {
	if (tree != NULL) {
		inOrder(tree->left);
		cout << tree->key << " ";
		inOrder(tree->right);
	}
}
template<class T>      //後遍歷RB樹
void RBTree<T>::postOrder() {
	if (root == NULL)
		cout << "empty RBtree\n";
	else
		postOrder(root);
};
template<class T>		
void RBTree<T>::postOrder(RBTNode<T>* tree)const {
	if (tree != NULL) {
		postOrder(tree->left);
		postOrder(tree->right);
		cout << tree->key << " ";
	}
}

因爲RBTree這裏使用模板 ,因此不能將cpp和h文件的RBTree的聲明和實現分離
原因:
模板定義很特殊。由template<…> 處理的任何東西都意味着編譯器在當時不爲它分配存儲空間,它一直處於等待狀態直到被一個模板實例告知。
在編譯器和連接器的某一處,有一機制能去掉指定模板的多重定義。所以爲了容易使用,幾乎總是在頭文件中放置全部的模板聲明和定義。——《C++編程思想》第15章300頁處

紅黑樹測試

//test.cpp
#include"RBTree.h"
#include<iostream>
#include<vector>
using namespace std;
int main() 
{
	vector<int> nums{ 10,40,30,60,90,70,20,50,80,100};
	RBTree<int> tree;
	for (auto num : nums)
		tree.insert(num);
	tree.preOrder();
	cout << endl;
	tree.inOrder();
	cout << endl;
	tree.postOrder();
	cout << endl;
	cout << "查找key爲30的結點:\n";
	cout << endl<<tree.search(30)->key<<endl;
	cout << "刪除key爲100的結點\n";
	tree.remove(100);
	tree.preOrder();
	cout << endl;
	cout << "\n紅黑樹詳細信息:\n";
	tree.print();
	cin.get();
	return 0;
}

測試運行結果

60 30 10 20 40 50 80 70 90 100
10 20 30 40 50 60 70 80 90 100
20 10 50 40 30 70 100 90 80 60
查找key爲30的結點:

30
刪除key爲100的結點
60 30 10 20 40 50 80 70 90

紅黑樹詳細信息:
60(0) is root
30(1) is 60's left child
10(0) is 30's left child
20(1) is 10's right child
40(0) is 30's right child
50(1) is 40's right child
80(1) is 60's right child
70(0) is 80's left child
90(0) is 80's right child

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章