数据结构与算法_红黑树(二)

完善Insert函数,让它支持自动平衡
新插入的节点一定是红色的
当新插入的节点是外部孙子节点使,进行一次单旋转
在这里插入图片描述
当新插入的节点是内部孙子节点,进行一次双旋转
在这里插入图片描述通用的旋转函数
在这里插入图片描述
Except.h异常类

#pragma once
#include <string>

using namespace std;

class DSException {

	public:
		DSException(const string &msg = ""):message(msg) {}
		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) {}

};

Wrapper.h自定义引用类型类

#pragma once
#include "Except.h"

template <class Object>
class Cref {

	public:
		Cref():obj(NULL) {}
		explicit Cref( Object &x) : obj(&x) {}
		Object &get() const {
			if(isNull()) {
				throw NullPointerException();
			} else {
				return *obj;
			}
		}
		bool isNull() const {
			return obj == NULL;
		}
	private:
		Object *obj;
};

RedBlackTree.h

#pragma once
#include <iostream> 
#include "Except.h"
#include "Wrapper.h"
/*
*红黑树规则:
*1.每一个节点不是红色就是黑色
*2.根总是黑色的
*3.如果节点是红色,则他的子节点必须是黑色的
*4.从根到叶节点的每条路径,必须包含相同数目的黑色节点
*/

template <class Comparable>
class RedBlackTree;

template <class Comparable>
class RedBlackNode;

template <class Comparable>
class RedBlackTree {

	public:
		enum {
		    RED,BLACK
		};
		RedBlackTree(const Comparable &negInf);
		~RedBlackTree();
		void insert(const Comparable &x);
		Cref<Comparable> find(const Comparable &x);
		Cref<Comparable> findMin() const;
		Cref<Comparable> findMax() const;
		bool isEmpty() const;
		void makeEmpty();
		typedef RedBlackNode<Comparable> Node;
//private: 为了测试,临时改为共有属性 
public:
		Node *header;
		Node *nullNode;
		//当前节点
		Node *current;
		//当前节点的父节点
		Node *parent;
		//祖父节点
		Node *grand;
		//曾祖父节点
		Node *great;

		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 *theParent) const;
		void reclaimMemory(Node* t) const;

};

template <class Comparable>
class RedBlackNode {

//private: 为了测试,临时改为共有属性 
public:
		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() {

	delete nullNode;
	delete header;

}

template <class Comparable>
void RedBlackTree<Comparable>::insert(const Comparable &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;
		//一个节点两个孩子都是红色
		if(current->left->color == RED && current->right->color == RED) {
			handleReorient(x);
		}
	}
	if(current != nullNode) {
		throw DuplicateItemException();
	}
	current = new Node(x,nullNode,nullNode);
	if(x < parent->element) {
		parent->left = current;
	} else {
		parent->right = current;
	}
	handleReorient(x);

}

//带着左孩子向右移动
template <class Comparable>
void RedBlackTree<Comparable>::rotateWithLeftChild(Node* &k2) const {

	Node *k1 = k2->left;
	//横向移动
	k2->left = k1->right;
	//k2下降
	k1->right = k2;
	//k1上升成为根
	k2 = k1;

}

//带着右孩子向左移动
template <class Comparable>
void RedBlackTree<Comparable>::rotateWithRightChild(Node* &k1) const {

	Node *k2 = k1->right;
	//横向移动
	k1->right = k2->left;
	//k1下降
	k2->left = k1;
	//k2上升成为根
	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小于爷爷 且 item小于爸爸 则是左外部孙子
		*如果item大于爷爷 且 item大于爸爸 则是右外部孙子
		*外部孙子做单旋转
		*如果两个条件不同时满足则是内部孙子
		*内部孙子做爽旋转
		*/
		if(item < grand->element != item < parent->element) {
			//内部孙子加多一次旋转
			parent = rotate(item,grand);
		}
		current = rotate(item,great);
		current->color = BLACK;
	}
	header->right->color = BLACK;

}

//通用旋转函数
/*
*theParent是item的父节点,item为被旋转的节点
*旋转可能性:
*左子树像向转,左子树向右转
*右子树像向转,右子树向右转
*/
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>
Cref<Comparable> RedBlackTree<Comparable>::find(const Comparable &x) {

	nullNode->element = x;
	Node *curr = header->right;
	for(;;) {
		if(x < curr->element) {
			curr = curr->left;
		} else if(x > curr->element) {
			curr = curr->right;
		} else if(curr != nullNode) {
			return Cref<Comparable>(curr->element);
		} else {
			return Cref<Comparable>();
		}
	}

}

template <class Comparable>
Cref<Comparable> RedBlackTree<Comparable>::findMin() const {

	if(isEmpty()) {
		return Cref<Comparable>();
	}
	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->left != nullNode) {
		itr = itr->right;
	}
	return Cref<Comparable>(itr->element);

}

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 {

	if(t != t->left) {
		reclaimMemory(t->left);
		reclaimMemory(t->right);
		delete t;
	}

}

main.h

#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);
	cout << "根是:" << t.header->right->element << endl;
	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);
	cout << "根是:" << t.header->right->element << endl; 
	if(t.findMin().get() == 50)
		cout << "找到最小值" << endl;
	cout << t.header->right->left->element << endl; 
	cout << t.header->right->left->left->element << endl; 
	cout << t.header->right->left->left->right->element << endl; 
	return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值