红黑树C++实现

完整实现了一遍红黑树,程序就当作自己的笔记好了

红黑树,顾名思义,就是红黑相间的树,它借由红黑规则实现了二叉排序树的平衡。

红黑规则如下:

1.每个节点不是红就是黑

2.根总是黑色

3.若节点为红色,它的子节点必须为黑色

4.从根到叶的每条路径,必须包含相同数目的黑色节点

插入和删除节点时都要遵循红黑规则,具体表现如下:

1.首先所有新插入的节点都为红色

2.若新插入的节点的父节点为红色,则必须对红黑树进行调整

(1)旋转

    单旋转:插入节点为外部子孙节点

    双旋转:插入节点为内部子孙节点

(2)改变颜色

3.有两个红色子节点的节点也要进行处理

    自己变红,儿子都变黑


上面只是对红黑树的一个简单概述,具体学习还要看算法书,下面是红黑树的代码实现。

对红黑树进行中序遍历即可得到递增的序列,故红黑树是有序的。

RB_Tree.h

#ifndef RB_TREE_H_
#define RB_TREE_H_

template<class Compareble>
class RedBlackTree;

template<class Compareble>
class RedBlackNode;

template<class Compareble>
class RedBlackTree
{
public:
	RedBlackTree(const Compareble & negInf);
	~RedBlackTree();

	enum {RED,BLACK};	//利用枚举表示两种颜色

	typedef RedBlackNode<Compareble> Node;

	bool isEmpty() const;
	void makeEmpty();

	bool find(const Compareble & x) const;

	void insert(const Compareble & x);
	
//private:
	Node *header;	//头节点
	Node *nullNode;	//空节点

	Node *current;
	Node *parent;	//父节点
	Node *grand;	//祖父节点
	Node *great;	//曾祖父节点

	void reclaimMemory(Node *t) const;

	void rotateWithLeftChild(Node * &k2) const;
	void rotateWithRightChild(Node * &k1) const;
	void doubleRotateWithLeftChild(Node * &k3) const;
	void doubleRotateWithRightChild(Node * &k1) const;

	void handleReorient(const Compareble &item);
	RedBlackNode<Compareble> * rotate(const Compareble & item, Node *theParent) const;
};
//红黑树节点
template<class Compareble>
class RedBlackNode
{
public:
	Compareble		element;
	RedBlackNode	*left;
	RedBlackNode	*right;
	int				color;

	RedBlackNode(const Compareble & theElement = Compareble(),
		RedBlackNode *lt = NULL,
		RedBlackNode *rt = NULL,
		int c = RedBlackTree<Compareble>::BLACK)
		:element(theElement), left(lt), right(rt), color(c){}

	friend class RedBlackTree<Compareble>;	//将红黑树作为友元类用于操作私有对象
};


template<class Compareble>
RedBlackTree<Compareble>::RedBlackTree(const Compareble & negInf)
{
	nullNode = new Node();
	nullNode->left = nullNode->right = nullNode;

	header = new Node(negInf);
	header->left = header->right = nullNode;	//左右孩子都指向空节点
}

template<class Compareble>
RedBlackTree<Compareble>::~RedBlackTree()
{
	delete nullNode;
	delete header;
}

//向红黑树中插入数据,在插入过程中需要实现自动平衡
template<class Compareble>
void RedBlackTree<Compareble>::insert(const Compareble & x)
{
	current = parent = grand = header;
	nullNode->element = x;

	while (current->element != x)	//不能插入相同的数据
	{
		great = grand; grand = parent; parent = current;	//旧的元素往上升一辈
		current = x < current->element ? current->left : current->right;	//向下搜寻

		//1.如果当前节点的左右儿子都是红色,需要进行处理
		if (current->left->color == RED && current->right->color == RED)
			handleReorient(x);
	}

	if (current != nullNode)
		throw "element repeat!";

	current = new Node(x, nullNode, nullNode);
	if (x < parent->element)
		parent->left = current;
	else
		parent->right = current;

	//对于新插入节点也要进行处理
	handleReorient(x);
}

//向右旋转
template<class Compareble>
void RedBlackTree<Compareble>::rotateWithLeftChild(Node * &k2) const
{
	Node *k1 = k2->left;
	//横向移动
	k2->left = k1->right;
	//上升和下降
	k1->right = k2;
	k2 = k1;
}
//向左旋转
template<class Compareble>
void RedBlackTree<Compareble>::rotateWithRightChild(Node * &k1) const
{
	Node *k2 = k1->right;
	k1->right = k2->left;
	k2->left = k1;
	k1 = k2;
}
//向右双旋转
template<class Compareble>
void RedBlackTree<Compareble>::doubleRotateWithLeftChild(Node * &k3) const
{
	rotateWithRightChild(k3->left);
	rotateWithLeftChild(k3);
}

//向左双旋转
template<class Compareble>
void RedBlackTree<Compareble>::doubleRotateWithRightChild(Node * &k1) const
{
	rotateWithLeftChild(k1->right);
	rotateWithRightChild(k1);
}

//根据红黑规则调整红黑树
template<class Compareble>
void RedBlackTree<Compareble>::handleReorient(const Compareble &item)
{
	//变色
	//1.对于有两个红色子节点的节点进行变色处理
	current->color = RED;
	current->left->color = BLACK;
	current->right->color = BLACK;

	//2.当前节点的父节点为红色
	if (parent->color == RED)
	{
		//爷爷颜色变红
		grand->color = RED;
		//进行旋转处理
		//判断如果是内部孙子就有两次旋转,外部孙子一次旋转
		if (item < grand->element != item < parent->element)
			parent = rotate(item, grand);
		current = rotate(item, great);
		//旋转之后把当前节点变黑
		current->color = BLACK;
	}
	//根节点必须黑色
	header->right->color = BLACK;
}

//根据内容自动判断旋转方向:
//左子树向右转->LL
//左子树向左转->LR
//右子树向右转->RL
//右子树向左转->RR
//参数1:当前节点数据,参数2:祖父节点(应比当前item大两辈)
template<class Compareble>
RedBlackNode<Compareble> * RedBlackTree<Compareble>::rotate(const Compareble & item, Node *theParent) const
{
	if (item < theParent->element)	//左子树
	{
		//如果item小于theParent->left->element,证明item是左子孙,要向右转
		item < theParent->left->element ?
			rotateWithLeftChild(theParent->left) :
			rotateWithRightChild(theParent->left);

		return theParent->left;
	}
	else	//右子树
	{
		item < theParent->right->element ?
			rotateWithLeftChild(theParent->right) :
			rotateWithRightChild(theParent->right);

		return theParent->right;
	}
}
//判断红黑树是否为空
template<class Compareble>
bool RedBlackTree<Compareble>::isEmpty() const
{
	return header->right == nullNode;
}

//清空红黑树
template<class Compareble>
void RedBlackTree<Compareble>::makeEmpty()
{
	reclaimMemory(header->right);
	header->right = nullNode;
}

template<class Compareble>
void RedBlackTree<Compareble>::reclaimMemory(Node *t) const
{
	//递归清除
	//t等于t->left时证明到底了停止递归(都是nullNode)
	if (t != t->left)
	{
		reclaimMemory(t->left);
		reclaimMemory(t->right);
		delete t;
	}
}

//清空红黑树
template<class Compareble>
bool RedBlackTree<Compareble>::find(const Compareble & x) const
{
	nullNode->element = x;

	Node *curr = header->right;

	while (1)
	{
		if (x < curr->element)
			curr = curr->left;
		else if (x>curr->element)
			curr = curr->right;
		else if (curr != nullNode)
			return true;
		else
			return false;
	}
}

#endif

RB_Tree.cpp

//红黑树实现
#include <iostream>
#include "RB_Tree.h"

using namespace std;

int main()
{
	const int NEG_INF = -99999;
	//使用一个很大的负数作为头指针的值
	RedBlackTree<int> t(NEG_INF);
	t.insert(50);
	t.insert(40);
	t.insert(30);
	t.insert(20);

	//如果不是红黑树,上面的输入会退化为链表,下面是验证过程
	cout << "第一层:" << t.header->right->element << endl;
	cout << "第二层:" << t.header->right->left->element << " " << t.header->right->right->element << endl;
	cout << "第三层:" << t.header->right->left->left->element << endl;
	//查找数据
	cout << (t.find(20) ? "找到了" : "没找到") << endl;
	//清空数据
	cout << t.isEmpty() << endl;
	t.makeEmpty();
	cout << t.isEmpty() << endl;

	system("pause");
	return 0;
}


猜你喜欢

转载自blog.csdn.net/u012411498/article/details/80427572