红黑树实现详解

实践意义

在各方面,红黑树要比AVL树性能更好,用途也更广泛

map&set底层都主要靠红黑树

概念

性质

插入时,抽象图

cur为新插入

插入时颜色更新逻辑图

插入/旋转

插入时旋转操作同AVL树, 不同点即不用修改平衡因子, 但需要改变节点颜色, 具体可见文末代码

AVL/红黑树旋转方法:AVL解析-CSDN博客

板书

手动实现源代码

#include <iostream>
#include <assert.h>
using namespace std;


enum COLOUR
{
	RED,
	BLACK
};

template<class T>
struct RBTreeNode
{
	RBTreeNode(const T& data = T())
		: _pLeft(nullptr)
		, _pRight(nullptr)
		, _pParent(nullptr)
		, _colour(RED)
		, _data(data)
		{; }

	RBTreeNode<T>* _pLeft;
	RBTreeNode<T>* _pRight;
	RBTreeNode<T>* _pParent;
	COLOUR _colour = RED;
	T _data;
};


// 请模拟实现红黑树的插入--注意:为了后序封装map和set,本文在实现时给红黑树多增加了一个头结点
template<class T>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	RBTree()
	{
		_pRoot = nullptr;
	}
	void Inorder()
	{
		_Inorder(_pRoot);
	}

	// 在红黑树中插入值为data的节点,插入成功返回true,否则返回false
	// 注意:为了简单起见,本次实现红黑树不存储重复性元素
	bool Insert(const T& data)
	{
		if (_pRoot == nullptr)
		{
			_pRoot = new Node(data);
			_pRoot->_colour = BLACK;
			return true;
		}
		//_pRoot不为空
		Node* cur = _pRoot, * parent = nullptr;
		while (cur)
		{
			if (cur->_data == data)//重复data
			{
				return false;
			}
			//data不重复
			if (data > cur->_data)//cur右走
			{
				parent = cur;
				cur = cur->_pRight;
			}
			else//cur往左走
			{
				parent = cur;
				cur = cur->_pLeft;
			}
		}
		cur = new Node(data);
		if (data < parent->_data)//cur 在 parent 左
		{
			parent->_pLeft = cur;
			cur->_pParent = parent;
		}
		else//cur在 右
		{
			parent->_pRight = cur;
			cur->_pParent = parent;
		}
		//更新整个树的_colour
		while (cur)//只有parent为黑或旋转后才可break
		{
			if (cur == _pRoot)
			{
				cur->_colour == BLACK;
				break;
			}
			Node* parent = cur->_pParent;
			if (parent->_colour == BLACK)
			{
				break;
			}
			//parent为红 , 必有grand
			Node* grand = parent->_pParent;
			Node* uncle = grand->_pRight;
			if (parent == grand->_pRight) uncle = grand->_pLeft;
			//以下主要看 uncle的color, 决定变色/旋转
			if (uncle && uncle->_colour == RED)//变色即可
			{
				uncle->_colour = BLACK;
				parent->_colour = BLACK;
				grand->_colour = RED;
				cur = grand;//继续向上更新, 不break
				if (cur == _pRoot)
				{
					cur->_colour == BLACK;
					break;
				}
				continue;
			}
			else //uncle为黑或unclue不存在, 旋转
			{
				if (parent == grand->_pLeft)
				{
					if (cur == parent->_pLeft)//右单旋
					{
						RotateR(grand);
						parent->_colour = BLACK;
						grand->_colour = cur->_colour = RED;
					}
					else//左右双旋
					{
						RotateLR(grand);
						cur->_colour = BLACK;
						parent->_colour = grand->_colour = RED;
					}
				}
				else
				{
					if (cur == parent->_pRight)//左单旋
					{
						RotateL(grand);
						parent->_colour = BLACK;
						grand->_colour = cur->_colour = RED;
					}
					else//右左单旋
					{
						RotateRL(grand);
						cur->_colour = BLACK;
						parent->_colour = grand->_colour = RED;
					}
				}
				break;
			}
		}
		_pRoot->_colour = BLACK;
	}

	// 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
	Node* Find(const T& data)
	{
		Node* cur = _pRoot;
		while (cur)
		{
			if (data == cur->_data)
			{
				return cur;
			}
			else if (data < cur->_data)
			{
				cur = cur->_pLeft;
			}
			else
			{
				cur = cur->_pRight;
			}
		}
		return nullptr;
	}

	// 获取红黑树最左侧节点
	Node* LeftMost()
	{
		Node* cur = _pRoot;
		while (cur->_pLeft)
		{
			cur = cur->_pLeft;
		}
		return cur;
	}

	// 获取红黑树最右侧节点
	Node* RightMost()
	{
		Node* cur = _pRoot;
		while (cur->_pRight)
		{
			cur = cur->_pRight;
		}
		return cur;
	}

	// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
	bool IsValidRBTRee()
	{//黑色个数算上_pRoot
		if (!_pRoot) return true;
		int pathBlack = 0;
		Node* cur = _pRoot;
		while (cur)
		{
			if (cur->_colour == BLACK)
			{
				pathBlack++;
			}
			cur = cur->_pLeft;
		}
		return _IsValidRBTRee(_pRoot, 0, pathBlack);
	}
private:
	bool _IsValidRBTRee(Node* root, size_t blackCount, size_t pathBlack)
	{
		if (!root)
		{
			return blackCount == pathBlack;
		}
		int add = root->_colour == BLACK ? 1 : 0;
		return _IsValidRBTRee(root->_pLeft, blackCount+add, pathBlack) && _IsValidRBTRee(root->_pRight, blackCount + add, pathBlack);
	}
	// 左单旋
	void RotateL(Node* grand)
	{
		Node* subR = grand->_pRight;
		Node* subRL = subR->_pLeft;
		if (grand == _pRoot)
		{
			_pRoot = subR;
			subR->_pParent = nullptr;
		}
		else
		{
			subR->_pParent = grand->_pParent;
			if (grand == grand->_pParent->_pLeft)
			{
				grand->_pParent->_pLeft = subR;
			}
			else
			{
				grand->_pParent->_pRight = subR;
			}
		}
		grand->_pRight = subRL; if (subRL) subRL->_pParent = grand;
		grand->_pParent = subR, subR->_pLeft = grand;
	}
	// 右单旋
	void RotateR(Node* grand)//旋转不变颜色, 函数外变颜色
	{
		Node* subL = grand->_pLeft;
		Node* subLR = subL->_pRight;
		if (grand == _pRoot)
		{
			_pRoot = subL;
			subL->_pParent = nullptr;
		}
		else
		{
			subL->_pParent = grand->_pParent;
			if (grand == grand->_pParent->_pLeft)
			{
				grand->_pParent->_pLeft = subL;
			}
			else
			{
				grand->_pParent->_pRight = subL;
			}
		}
		grand->_pLeft = subLR; if(subLR) subLR->_pParent = grand;
		grand->_pParent = subL, subL->_pRight = grand;
		
	}
	void RotateLR(Node* grand)
	{
		RotateL(grand->_pLeft);
		RotateR(grand);
	}
	void RotateRL(Node* grand)
	{
		RotateR(grand->_pRight);
		RotateL(grand);
	}
	
private:
	Node* _pRoot;
	void _Inorder(Node* root)
	{
		if (!root) return;
		_Inorder(root->_pLeft);
		cout << root->_data << " ";
		_Inorder(root->_pRight);
	}
};

void testRBTree()
{
	RBTree<int> rb;
	rb.Insert(2);
	rb.Insert(6);
	rb.Insert(4);
	rb.Insert(9);
	rb.Insert(11);
	rb.Insert(78);
	rb.Insert(36);
	rb.Insert(27);
	rb.Inorder();
	cout << endl;
	int array[10] = { 1, 2, 6, 4, 9, 10, 11, 27, 55, 78 };
	for (const auto& e : array)
	{
		auto find = rb.Find(e);
		if (!find)cout << e << " 不在树中" << endl;
		else
		{
			if (find->_data == e)
			{
				cout << e << " 在树中, 返回值正确" << endl;
			}
			else
			{
				cout << e << " 在树中, 但是返回值错误" << endl;
			}
		}
	}
	cout << rb.IsValidRBTRee() << endl;

	cout << "hello world" << endl;
}

int main()
{
	testRBTree();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值