红黑树

Wrapper.h

#ifndef WRAPPER_H_
#define WRAPPER_H_

#include "Except.h"

template <class Object>
class Cref
{
public:
	Cref() : obj(NULL) {}
	//防止隐式转换
	//refer:https://baike.baidu.com/item/explicit/4941869?fr=aladdin
	//      https://bbs.csdn.net/topics/390244071
	//以Object为int为例,
	//当不加explicit时,int i1 = 8; Cref c1 = i1;是可以的,会调用构造函数
	//当加explicit时,int i1 = 8; Cref c1 = i1;错误,不允许调用构造函数
	explicit Cref(const Object & x) : obj(&x) {}

	const Object & get() const
	{
		if(isNull()) throw NullPointerException(); else return *obj;
	}

	bool isNull() const
	{
		return obj == NULL;
	}
private:
	const Object *obj;
};

#endif

except.h


#ifndef EXCEPT_H_
#define EXCEPT_H_

#include <string>

using namespace std;
//基础异常,用于继承
class DSException  
{
public:
	DSException(const string & msg = "") : message(msg){}
	//当有子类时,析构函数必须要定义为虚函数,否则会导致释放不完全
	//refer:https://blog.csdn.net/mohuan301/article/details/83746943
	virtual ~DSException(){}
	virtual string toString() const
	{
		return "Exception " + string(": ") + what();
	}
	virtual string what() const
	{
		return message;
	}
private:
	string message;
};

class DuplicateItemException : public DSException
{
public:
	DuplicateItemException(const string & msg = "") : DSException(msg) {}
};

class NullPointerException : public DSException
{
public:
	NullPointerException(const string & msg = "") : DSException(msg){}
};
#endif

RedBlackTree.h

#ifndef RED_BLACK_TREE_H_
#define RED_BLACK_TREE_H_

#include "Except.h"
#include "Wrapper.h"

template <class Comparable>
class RedBlackTree;

template <class Comparable>
class RedBlackNode;

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

	Cref<Comparable> find(const Comparable & x) const;
	Cref<Comparable> findMin() const;
	Cref<Comparable> findMax() const;
	bool isEmpty() const;
	void makeEmpty();

	enum {RED,BLACK};

	void insert(const Comparable & x);

	typedef RedBlackNode<Comparable> Node;
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 Comparable & item);
	RedBlackNode<Comparable> * rotate(const Comparable & item, Node *parent) const;

};

template <class Comparable>
class RedBlackNode
{
private: 
	Comparable		element;
	RedBlackNode	*left;
	RedBlackNode	*right;
	int				color;

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

	friend class RedBlackTree<Comparable>;
};

//创建了一个头结点和空节点,其中让所有节点的孩子节点都为空节点
template <class Comparable>
RedBlackTree<Comparable>::RedBlackTree(const Comparable & negInf)
{
	nullNode = new Node();
	nullNode->left = nullNode->right = nullNode;
	header = new Node(negInf);
	header->left = header->right = nullNode;
}


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


template <class Comparable>
//插入过程其实就是先将nullNode的值设置为x,而每个叶子节点的孩子都是nullNode,所以换句话说,在红黑树
//中一定可以找到x,而当下面的while循环退出时,如果current是nullNode,表明找到了nullNode中的x,这时候
//current就应该是要插入的地方,而如果current不是nullNode,表明找到了除nullNode外其他值为x的结点
//这就表明有重复的值
void RedBlackTree<Comparable>::insert(const Comparable & x)
{
	current = parent = grand = header;
	nullNode->element = x;

	while(current->element != x)
	{
		great = grand; grand = parent; parent = current;
		//header给一个特别小的复数就是为了让所有的值都向右子树走
		current = x < current->element ? current->left : current->right;

		if(current->left->color == RED && current->right->color == RED)
			handleReorient(x);
	}

	if(current != nullNode)
		throw DuplicateItemException();
	
	current = new Node(x,nullNode,nullNode);
	//因为上面current = x < current->element ? current->left : current->right;表明current可能是
	//current = current->left过来的,也可能是current = current->right过来的,所以需要先判断到底
	//是父结点的左孩子还是右孩子,这样需要将自己设为左孩子还是右孩子
	if(x < parent->element)
		parent->left = current;
	else
		parent->right = current;

	handleReorient(x);
}

template <class Comparable>
void RedBlackTree<Comparable>::rotateWithLeftChild(Node * & mainNode) const
{
	Node *futureMainNode = mainNode->left;
	mainNode->left = futureMainNode->right;
	futureMainNode->right = mainNode;
	mainNode = futureMainNode;   /*使用更改后的子树的跟来更改调用rotateWithLeftChild时传进来的原子树的根*/
}

template <class Comparable>
void RedBlackTree<Comparable>::rotateWithRightChild(Node * & k1) const
{
	Node *k2 = k1->right;
	k1->right = k2->left;
	k2->left = k1;
	k1 = k2;
}

template <class Comparable>
void RedBlackTree<Comparable>::doubleRotateWithLeftChild(Node * & k3) const
{
	rotateWithRightChild(k3->left);
	rotateWithLeftChild(k3);
}

template <class Comparable>
void RedBlackTree<Comparable>::doubleRotateWithRightChild(Node * & k1) const
{
	rotateWithLeftChild(k1->right);
	rotateWithRightChild(k1);
}

template <class Comparable>
void RedBlackTree<Comparable>::handleReorient(const Comparable & item)
{
	//新插入的结点是红的,左右是黑的
	//当一个结点有两个红孩子,则将这个结点设为红的,两个孩子设为黑的
	current->color = RED;
	current->left->color = BLACK;
	current->right->color = BLACK;

	if(parent->color == RED)/*当父节点是红时,则违反规则,调整*/
	{
		grand->color = RED;
		//判断item即将插入的地方是否是内结点(即爷爷的内结点),如果是则需要进行双旋转
		//以爷爷旋转一次,再以曾祖父进行旋转
		//如果不是则需要进行单旋转(只以爷爷进行旋转)
		//如果一个结点比爷爷大,比爸爸大,或者比爷爷小,比爸爸小,则是外部,
		if(item < grand->element != item < parent->element)
			parent = rotate(item,grand);
		current = rotate(item,great);
		current->color = BLACK;
	}
	//红黑树的根一定是黑的
	header->right->color = BLACK;
}

template <class Comparable>
RedBlackNode<Comparable> * RedBlackTree<Comparable>::rotate(const Comparable & item, Node * theParent) const
{
	if(item < theParent->element)
	{
		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 Comparable>
bool RedBlackTree<Comparable>::isEmpty() const
{
	return header->right == nullNode;
}

//释放红黑树
template <class Comparable>
void RedBlackTree<Comparable>::makeEmpty()
{
	reclaimMemory(header->right);
	header->right = nullNode;
}

//释放红黑树
template <class Comparable>
void RedBlackTree<Comparable>::reclaimMemory(Node* t) const
{
	//当t不是一个节点的时候即递归终止,即t是叶子节点的孩子的时候递归终止,而叶子节点的孩子即为nullNode,而nullNode的孩子也是nullNode
	//所以这里t!=t->left就是判断t是否是叶子节点的孩子,如果是表明这时候叶子节点及他们的父节点都释放了,所以就不不需要再释放
	if(t != t->left)
	{
		reclaimMemory(t->left);
		reclaimMemory(t->right);
		delete t;
	}
}

template <class Comparable>
Cref<Comparable> RedBlackTree<Comparable>::findMin() const
{
	if(isEmpty())
		return Cref<Comparable>(); /*默认构造,返回null*/

	Node *itr = header->right;
	while(itr->left != nullNode)
		itr = itr->left;

	return Cref<Comparable>(itr->element);

}

template <class Comparable>
Cref<Comparable> RedBlackTree<Comparable>::findMax() const
{
	if(isEmpty())
		return Cref<Comparable>();

	Node *itr = header->right;
	while(itr->right != nullNode)
		itr = itr->right;

	return Cref<Comparable>(itr->element);
};

template <class Comparable>
Cref<Comparable> RedBlackTree<Comparable>::find(const Comparable & x) const
{
	nullNode->element = x;

	Node *curr = header->right;

	while (true) {
		if (curr == nullNode)
			return Cref<Comparable>(curr->element);
		else if (x != curr->element)
			return Cref<Comparable>(curr->element);
		else if (x < curr->element)
			curr = curr->left;
		else if (x > curr->element)
			curr = curr->right;
		else {
			cout << "有种情况没有考虑到哦" << endl;
			system("pause");
		}
	}
}

#endif

main.cpp

#include <iostream>
#include "RedBlackTree.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);
	
	//cout << t.header->right->element << endl;

	if(!t.isEmpty()) cout << "红黑树不是空的" << endl;

	t.makeEmpty();
	if(t.isEmpty()) cout << "红黑树是空的" << endl;

	t.insert(200);
	t.insert(100);
	t.insert(90);
	t.insert(50);
	t.insert(80);
	t.insert(70);
	t.insert(60);

	if(t.findMin().get() == 50) cout << "找到了最小的数" << endl;

	cout << "最大的: " << t.findMax().get() << endl;

	Cref<int> r = t.find(80);

	if(r.isNull())
	{
		cout << "没找到!" << endl;
	}
	else
	{
		cout << "找到: " << r.get() << endl;
	}

	cout << "OK" << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
图片选自于:https://www.cnblogs.com/hzmark/archive/2012/12/31/Tree.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值