红黑树的C++编程实现

花了两天的时间看了有关红黑树的特性及相关插入与删除的图例操作,自己编写了一下红黑树,用一个顺序排列的数组进行建树,再对其中一些关键的结点进行删除测试,经过不断的调试修改完成了红黑树类的编写,实现树的插入、删除、前根遍历、中根遍历、后根遍历、输出最大值/最小值、查找、简单输出树结构等各个功能。类提供了简单的外部接口。类为模板类。

红黑树的特性:1、根节点为黑色

                            2、空的叶子结点(外部结点)都为黑色

                            3、结点为红色时,其子女结点必须为黑色,即不能出现连续的红色

                            4、从任意结点到其外部结点的路径上的黑色数目是相同的

#ifndef _RBTREE_H
#define _RBTREE_H

#include <iostream>
#include <iomanip>

using std::setw;       

enum RBTColor {RED, BLACK};

template <class T>
struct RBTNode {                  //树的结点结构
	RBTColor color;               //颜色
	T key;						  //键值
	RBTNode* left;				  //左孩子
	RBTNode* right;				  //右孩子
	RBTNode* parent;			  //父节点
};

template <class T>
class RBTree {
private:
	RBTNode<T>* mRoot;			//根节点

public:
	RBTree();
	~RBTree();

    //以下为外部接口
	void preOrder();			//前根遍历
	void inOrder();				//中根遍历
	void postOrder();			//后根遍历

	RBTNode<T>* search(T key);	//寻值
	
	T minimum() const;				//最小值
	T maximum() const;				//最大值

	void insert(T key);			//插入值
	void remove(T key);			//移除值

	void destory();				//销毁树
	void print();				//打印树

private:
    //以下为内部接口
	void preOrder(RBTNode<T>* tree) const;       //前根遍历
	void inOrder(RBTNode<T>* tree) const;		 //中根遍历
	void postOrder(RBTNode<T>* tree) const;		 //后根遍历

	RBTNode<T>* search(RBTNode<T>* x, T key) const;      //寻值
	
	RBTNode<T> *minimum(RBTNode<T>* tree) const;				 //最小值
	RBTNode<T> *maximum(RBTNode<T>* tree) const;			 	 //最大值

	void leftRotate(RBTNode<T>* &root, RBTNode<T>* x);   //左旋
	void rightRotate(RBTNode<T>* &root, RBTNode<T>* x);	 //右旋
	void insert(RBTNode<T>* &root, RBTNode<T>* node);	 //插入值
	void remove(RBTNode<T>* &root, RBTNode<T>* node);	 //移除值
	
	void insertFixUp(RBTNode<T>* &root, RBTNode<T>* node);	//插入修正函数
	void removeFixUp(RBTNode<T>* &root, RBTNode<T>* node, RBTNode<T>* parent); //删除修正函数

	void destroy(RBTNode<T>* &tree);					//销毁树
	void print(RBTNode<T>* tree);                       //打印树
};

using std::cout;
using std::endl;

//以下的遍历和寻值都是采用递归的方式
template<class T>
void RBTree<T>::preOrder(RBTNode<T>* tree) const       //前根遍历
{
	if (tree == NULL) return;
	cout << tree->key << " ";
	preOrder(tree->left);
	preOrder(tree->right);
}

template<class T>
void RBTree<T>::inOrder(RBTNode<T>* tree) const		 //中根遍历
{
	if (tree == NULL) return;
	inOrder(tree->left);
	cout << tree->key << " ";
	inOrder(tree->right);
}

template<class T>
void RBTree<T>::postOrder(RBTNode<T>* tree) const		 //后根遍历
{
	if (tree == NULL) return;
	postOrder(tree->left);
	postOrder(tree->right);
	cout << tree->key << " ";
}

template<class T>
RBTNode<T>* RBTree<T>::search(RBTNode<T>* x, T key) const      //寻值
{
	if (x == NULL) return NULL;
	if (key == x->key) return x;
	else if (key > x->key) search(x->right, key);
	else search(x->left, key);
}

template<class T>
RBTNode<T>* RBTree<T>::minimum(RBTNode<T>* tree) const			 //最小值
{
	RBTNode<T>* node = tree;
	while (node->left != NULL)
		node = node->left;
	return node;
}

template<class T>
RBTNode<T>* RBTree<T>::maximum(RBTNode<T>* tree) const			 	 //最大值
{
	RBTNode<T>* node = tree;
	while (node->right != NULL)
		node = node->right;
	return node;
}

//左旋与右旋建议通过画图,边看代码边看图中各结点的改变,两个是对称的
template<class T>
void RBTree<T>::leftRotate(RBTNode<T>* &root, RBTNode<T>* x)   //左旋
{
	RBTNode<T>* parent = x->parent;
	RBTNode<T>* x_pos = x->right;        //代替旋转结点处的结点

	x->right = x_pos->left;
	x_pos->left = x;
	x->parent = x_pos;
	if (x->right) x->right->parent = x;
	x_pos->parent = parent;
	if (parent) {
		if (parent->left == x) parent->left = x_pos;
		else parent->right = x_pos;
	}
	else
		root = x_pos;
}

template<class T>
void RBTree<T>::rightRotate(RBTNode<T>* &root, RBTNode<T>* x)	 //右旋
{
	RBTNode<T>* parent = x->parent;
	RBTNode<T>* x_pos = x->left;

	x->left = x_pos->right;
	x_pos->right = x;
	x->parent = x_pos;
	if (x->left) x->left->parent = x;
	x_pos->parent = parent;
	if (parent) {
		if (parent->left == x) parent->left = x_pos;
		else parent->right = x_pos;
	}
	else
		root = x_pos;
}

//先将结点插入到树中,在对树进行调整
template<class T>
void RBTree<T>::insert(RBTNode<T>* &root, RBTNode<T>* node)	 //插入结点
{
	if (search(node->key)) return;
	RBTNode<T>* x = root;
	RBTNode<T>* parent = NULL;

	while (x) {                      //找到插入结点的父母结点
		parent = x;
		if (node->key > x->key)
			x = x->right;
		else
			x = x->left;
	}

	if (parent) {                    //将插入结点连接到父母结点
		if (node->key > parent->key)
			parent->right = node;
		else
			parent->left = node;
	}
	else
		root = node;                //若无父母结点,则该结点为根结点

	node->color = RED;              //将该结点的颜色初始化为红色
	node->parent = parent;          

	insertFixUp(root, node);        //插入修正
}

//删除结点需对树进行调整,再将结点删除,所以此函数较简单
template<class T>
void RBTree<T>::remove(RBTNode<T>* &root, RBTNode<T>* node)	 //移除结点
{
	removeFixUp(root, node, node->parent);   //删除修正
}


template<class T>
void RBTree<T>::insertFixUp(RBTNode<T>* &root, RBTNode<T>* node)	//插入修正函数
{
	if (root == node) {              //若插入结点为根结点,则将根结点的颜色改为黑即可
		root->color = BLACK;
		return;
	}

	RBTNode<T>* parent = node->parent;
	if (parent->color == BLACK) {     //若父母结点为黑色,则将根结点改为黑即可
		root->color = BLACK;
		return;
	}

    //以下为父母结点为红色的操作,建议画图
	RBTNode<T>* gparent = parent->parent;
	RBTNode<T>* uncle = (parent == gparent->right) ? gparent->left : gparent->right;
	if (uncle) {    
		if (uncle->color == BLACK) {    //叔叔结点为黑色,需进行旋转
			if (parent == gparent->left)
				rightRotate(root, gparent);
			else
				leftRotate(root, gparent);

			gparent->color = RED;        //重新上色
			parent->color = BLACK;
		}
		else {    //叔叔结点为红色,则重新上色,将长辈结点视为新插入的结点,重新进行插入修正
			parent->color = BLACK;
			uncle->color = BLACK;
			gparent->color = RED;
			insertFixUp(root, gparent);
		}
	}
	else {  //若不存在叔叔结点,则属于三结点一线的情况,需对三结点进行调整,成为三足鼎立的样子
        //三结点成一直线的情况
		if ((node == parent->left && parent == gparent->left) || (node == parent->right && parent == gparent->right)) {
			if (node == parent->left) parent->right = gparent;
			else parent->left = gparent;
			parent->parent = gparent->parent;
			if (gparent->parent) {
				if (gparent->parent->left == gparent) gparent->parent->left = parent;
				else gparent->parent->right = parent;
			}
			else {
				root = parent;
			}
			gparent->parent = parent;
			gparent->left = NULL;
			gparent->right = NULL;
			gparent->color = RED;        //重新上色
			parent->color = BLACK;
		}
        //三结点成一折线的情况
		else {
			T tmp = node->key;
			node->key = gparent->key;
			gparent->key = tmp;
			if (gparent->left == parent) gparent->right = node;
			else gparent->left = node;
			parent->left = NULL;
			parent->right = NULL;
			node->parent = gparent;
		}
	}

	root->color = BLACK;        //将根结点改为黑色
}

template<class T>
void RBTree<T>::removeFixUp(RBTNode<T>* &root, RBTNode<T>* node, RBTNode<T>* parent)	//删除修正函数
{
	if (node->left == NULL && node->right == NULL) {    //无子女结点的处理
		if (parent == NULL) {            //无父母结点,即为根结点,删除根节点即可
			root = NULL;
			return;
		}
		if (node->color == RED) {        //删除结点为红色,不破坏树的结构,直接删除即可
			if (parent->left == node) parent->left = NULL;
			else parent->right = NULL;
			delete node;
			return;
		}
		else {        //删除结点为黑色的处理,较为复杂
			RBTNode<T>* brother = (parent->left == node) ? parent->right : parent->left;
			if (parent->color == RED) {    //父母结点为红色,则删除结点后不会出现双黑结点
                //兄弟结点有子女时,需旋转调整结构,避免失衡
				if (brother->right || brother->left) {    
					if (parent->left == node) leftRotate(root, parent);
					else rightRotate(root, parent);
					RBTNode<T>* gparent = parent->parent;
					gparent->color = RED;      //重新上色
					gparent->left->color = BLACK;
					gparent->right->color = BLACK;
				}
                //兄弟结点无子女则重新上色即可
				else {
					parent->color = BLACK;
					parent->left->color = RED;
					parent->right->color = RED;
				}
			}
            /*父母结点为黑色,则删除结点后会出现双黑结点,所以需通过旋转改变删除结点的位置使其不         
              为双黑结点,在对其进行删除*/
			else {    
                //兄弟结点为红色,则通过旋转改变删除点的位置
				if (brother->color == RED) {
					if (parent->left == node) leftRotate(root, parent);
					else rightRotate(root, parent);
					RBTNode<T>* gparent = brother->parent;
                    //重新上色
					if (gparent->left == brother) gparent->right->color = RED;
					else gparent->left->color = RED;
					parent->left->color = RED;
					parent->right->color = RED;
				}
				else {    //兄弟结点为黑色
                    //兄弟结点有子女,对父母结点进行旋转
					if (brother->left || brother->right) {
						if (parent->left == node) leftRotate(root, parent);
						else rightRotate(root, parent);
						brother->left->color = BLACK;
						brother->right->color = BLACK;
					}
                    //兄弟结点无子女时,需对父辈结点进行旋转
					else {
						RBTNode<T>* gparent = parent->parent;
						RBTNode<T>* uncle = (gparent->left == parent) ? gparent->right : gparent->left;
						if (uncle->key > parent->key) leftRotate(root, gparent);
						else rightRotate(root, gparent);
						if (uncle->color == BLACK) {    //以下为重新上色
							gparent->color = RED;
							brother->color = RED;
						}
						else{
							uncle->color = BLACK;
							brother->color = RED;
							uncle = (gparent->left == parent) ? gparent->right : gparent->left;
							if (uncle->left) uncle->left->color = RED;
							if (uncle->right) uncle->right->color = RED;
						}
					}
				}
			}
            //删除该结点
			if (parent->left == node) parent->left = NULL;
			else parent->right = NULL;
			delete node;
		}
	}
    //有一子女的结点,将该子女结点代替删除的结点,在将子女结点进行删除即可
	else if (node->left == NULL || node->right == NULL) {
		RBTNode<T>* node_child = (node->left) ? node->left : node->right;
		node->key = node_child->key;
		removeFixUp(root, node_child, node);
	}
    //有两子女的结点,将子孙结点中值最靠近删除结点的结点代替删除的结点,在将该子孙结点删除即可
	else {
		RBTNode<T>* node_child = node->right;
		while (node_child->left) {
			node_child = node_child->left;
		}
		node->key = node_child->key;
		removeFixUp(root, node_child, node_child->parent);
	}
}

//采用递归的方式对树进行销毁
template<class T>
void RBTree<T>::destroy(RBTNode<T>* &tree)					//销毁树
{
	if (tree == NULL) return;
	destory(tree->left);
	destory(tree->right);
	delete tree;
}

//对树的结构进行简单的打印
template<class T>
void RBTree<T>::print(RBTNode<T>* tree) //打印树
{
	if (tree == NULL) return;
	static char color[] = { 'R', 'B' };
	RBTNode<T>* parent = tree->parent;
	if (parent == NULL) cout << tree->key << "(" << color[tree->color] << ") is root" << endl;
	else {
		const char* dir = (parent->left == tree) ? "left" : "right";
		cout << setw(3) << right << tree->key;
		cout << "(" << color[tree->color] << ") is ";
		cout << setw(3) << right << parent->key << "'s ";
		cout << setw(7) << right << dir << " child" << endl;
	}

	print(tree->left);
	print(tree->right);
}

//构造函数
template<class T>
RBTree<T>::RBTree()
{
	this->mRoot = NULL;
}

//析构函数
template<class T>
RBTree<T>::~RBTree()
{
	this->destory();
}

//以下为外部接口,函数编写较简单,即调用内部接口
template<class T>
void RBTree<T>::preOrder()			//前根遍历
{
	this->preOrder(this->mRoot);
}

template<class T>
void RBTree<T>::inOrder()				//中根遍历
{
	this->inOrder(this->mRoot);
}

template<class T>
void RBTree<T>::postOrder()			//后根遍历
{
	this->postOrder(this->mRoot);
}

template<class T>
RBTNode<T>* RBTree<T>::search(T key)	//寻值
{
	return this->search(this->mRoot, key);
}

template<class T>
T RBTree<T>::minimum() const				//最小值
{
	RBTNode<T>* node = this->minimum(this->mRoot);
	return node->key;
}

template<class T>
T RBTree<T>::maximum() const				//最大值
{
	RBTNode<T>* node = this->maximum(this->mRoot);
	return node->key;
}

template<class T>
void RBTree<T>::insert(T key)			//插入值
{
	RBTNode<T>* node = new RBTNode<T>;
	node->left = NULL;
	node->right = NULL;
	node->parent = NULL;
	node->color = BLACK;
	node->key = key;

	this->insert(this->mRoot, node);
}

template<class T>
void RBTree<T>::remove(T key)			//移除值
{
	RBTNode<T>* node = this->search(key);
	if(node)
		this->remove(this->mRoot, node);
}

template<class T>
void RBTree<T>::destory()				//销毁树
{
	this->destory(this->mRoot);
}

template<class T>
void RBTree<T>::print()				//打印树
{
	this->print(this->mRoot);
}

#endif

原本是将类的声明和定义放在两个文件的,但是调试的时候出现 无法解析的外部符号 的错误,百度之后发现因为类是模板类,编译器无法找到特化实例,因此不生成任何可执行实例代码,从而导致出现此问题。将声明和定义放在同个文件后即可通过编译。具体原因可看:https://blog.csdn.net/big_bit/article/details/52289162

最后附上测试时用的例子

#include <iostream>
#include "RBTree.h"

using namespace std;

int main() {
	int num[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
	int i = 0;

	RBTree<int>* tree = new RBTree<int>();
	int len = sizeof(num) / sizeof(num[0]);
	//for (i = len - 1; i >= 0; i--) {        //正反都进行测试
	for (i = 0; i < len; i++) {
		tree->insert(num[i]);
		//tree->print();        //输出每一次插入值时的树结构,便于观察哪一次出错
		//cout << endl;
	}

	tree->preOrder();
	cout << endl;
	tree->inOrder();
	cout << endl;
	tree->postOrder();
	cout << endl;

	cout << tree->maximum() << endl;
	cout << tree->minimum() << endl;

	tree->print();

	tree->remove(1);
	tree->remove(2);
	tree->remove(3);
	tree->print();

	system("pause");

	return 0;
}

最后的最后如果有人用上面的代码进行测试,出错的话欢迎在评论中告诉我,感谢

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值