笔记——红黑树

红黑树规则

每个节点不是黑色就是虹色

根节点为黑色

每条路径的黑节点之和相等

每个红节点一定和黑节点相连,黑节点可以和任意节点相连

最长路径小于等于最短路径的二倍

插入一个节点后,怎么保持原有规则

更新祖宗节点的颜色

grandpa

parent uncle

cur

cur为被插入节点,

如果parent存在,且parent的颜色为黑,停止更新

根据uncle的存在或是颜色来判断是否更新颜色 还是 进行旋转以保持原有规则

如果parent节点的颜色为红色,且uncle节点存在颜色为红色,把parent和uncle节点颜色更新成黑色,将grandpa颜色更新成红色,令cur=grandpa,接着循环判断

旋转

如果parent节点的颜色为红色,uncle节点不存在或颜色为黑色,要进行旋转,旋转方式和AVLTree中情况相同

単旋和双旋

単旋就是节点一边高

双旋就是节点不单是一边高

右旋

左边节点高,进行右旋

grandpa

parent

cur

parent是grandpa的左孩子,cur是parent的左孩子,这种情况要右旋

grandpa

parent

cur

parent是grandpa的右孩子,cur是parent的左孩子,先右旋,在左旋

先将 parent 以parent为旋转点 ,进行右·旋

cur

得到 grandpa 以cur为旋转点,进行左旋

cur

parent

红黑树迭代器

新实现一个类(_iterator),在红黑树中实现begin()等函数,把_iterator在红黑树中重命名

++重载:由于红黑树是用中序遍历也就是 先遍历左子树,在遍历根,最后遍历右子树,

也就是说红黑中的一个节点++后,

如果有右子树,就会跑到右子树最左节点

如果没有右子树,就要判断,根节点是父节点的左孩子还是右孩子,

如果是左孩子,就跑到父节点

如果是右孩子,则向上遍历,直到找到,或父节点为空(也就是到头)

把红黑树封装成set和map(要求只用一份红黑树代码)

Insert的返回类型为pair<iterator,bool>,返回iterator(迭代器)可以避免迭代器失效的情况,bool表示插入是否成功(返回1代表原数据没有,返回0代表存在)

在map和set类中,只需要调用红黑树中的函数即可

封装map和set就像是基类和子类的关系

子类在父类的基础上添加一些东西

代码部分

RedBlackTree.h

#pragma once
#include<iostream>
using namespace std;


enum Color
{
	RED,
	BLACK
};

template<class K, class V >
class RBNode
{
public:
	typedef RBNode<K, V>Node;

	Node* _left;
	Node* _right;
	Node* _parent;
	Color _color;
	pair<K, V>_kv;
public:
	RBNode(pair<K, V>kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _color(RED)
	{}
};

template<class K, class V>
class RBTree
{
public:
	typedef RBNode<K, V> Node;
private:
	Node* _root = nullptr;
public:


	//构造函数
	RBTree()
		:_root(nullptr)
	{}



	//析构函数
	void _Destory(Node* root)
	{
		if (root == nullptr)
			return;
		_Destory(root->_left);
		_Destory(root->_right);
		delete root;
	}
	~RBTree()
	{
		_Destory(_root);
	}


	//拷贝构造函数
	Node* _Copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* left = _Copy(root->_left);
		Node* right = _Copy(root->_right);
		Node* newnode = new Node;
		newnode->_left = left;
		newnode->_right = right;
		newnode->_color = root->_color;
		newnode->_kv = root->_kv;
		return newnode;

	}
	RBTree(const Node& t)
	{
		_Copy(&t);
	}


	//赋值
	RBTree<K, V>operator=(RBTree<K, V>t)
	{
		swap(_root, t._root);
		return *this;
	}



	//左旋

	void RotateL(Node* cur)
	{
		Node* parent = cur->_parent;
		Node* curL = cur->_left;
		Node* gradpa = parent->_parent;
		if (gradpa && gradpa->_left == parent)
			gradpa->_left = cur;
		if(gradpa && gradpa->_right == parent)
			gradpa->_right = cur;
		if (gradpa == nullptr)
			_root = cur;
		parent->_right = cur->_left;
		parent->_parent=cur;
		cur->_parent = gradpa;
		cur->_left = parent;

			
	}

	//右旋
	void RotateR(Node* cur)
	{
		Node* parent = cur->_parent;
		Node* curR = cur->_right;
		Node* gradpa = parent->_parent;
		if (gradpa && gradpa->_left == parent)
			gradpa->_left = cur;
		if (gradpa && gradpa->_right == parent)
			gradpa->_right = cur;
		parent->_left = curR;
		parent->_parent = cur;
		cur->_right = parent;
		cur->_parent = gradpa;
	}



	//插入
	bool Insert(pair<K, V>kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_color = BLACK;
			return true;
		}
		Node* cur = _root;
		//找到要插入的位置
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		
		cur= new Node(kv);
		
		Node* gradpa =nullptr;
		Node* uncle = nullptr;
		cur->_parent = parent;


		//判断单旋还是双旋
		if (parent->_kv.first > kv.first)
		{
			//新插入节点位置左边还是右边
			//新节点插入左边
			parent->_left = cur;
			//parent可能是根节点
			if (parent->_color == BLACK)
				return 1;
			//parent一定是红色,且一定有父节点
			 gradpa = parent->_parent;
			 //判断uncle和parent谁是左节点谁是右节点
			 if (parent == gradpa->_left)
				 uncle = gradpa->_right;
			 else
				 uncle = gradpa->_left;
		}
		else
		{
			//新节点插在右边
			parent->_right = cur;
			if (parent->_color == BLACK)
				return 1;
			gradpa = parent->_parent;
			if (parent == gradpa->_left)
				uncle = gradpa->_right;
			else
				uncle = gradpa->_left;
		}

		while (cur)
		{
			if (parent->_color == BLACK)
			{
				break;
			}
			else
			{
				//更新节点颜色
				if (uncle && uncle->_color == RED)
				{
					uncle->_color = parent->_color = BLACK;
					gradpa->_color = RED;
					cur = gradpa;
					parent = cur->_parent;

					if (parent == nullptr || parent->_color == BLACK)
						break;

					gradpa = parent->_parent;
					if (parent->_right == cur)
						uncle = gradpa->_left;
					else
						uncle = gradpa->_right;
				}
				//旋转
				else
				{
					if (cur == parent->_left)
					{
						if (parent == gradpa->_left)
						{
							RotateR(parent);
							gradpa->_color = RED;
							parent->_color = BLACK;
							break;

						}
						else
						{
							RotateR(cur);
							RotateL(cur);
							cur->_color = BLACK;
							gradpa->_color = RED;
							break;
						}
					}
					else
					{
						if (parent == gradpa->_right)
						{
							RotateL(parent);
							gradpa->_color = RED;
							parent->_color = BLACK;
							break;

						}
						else
						{
							RotateL(cur);
							RotateR(cur);
							cur->_color = BLACK;
							gradpa->_color = RED;
							break;
						}
					}
				}
			}
		}
		_root->_color = BLACK;
	}
	//中序遍历
	void _Inorder(Node* root)
	{
		if (root == nullptr)
			return;
		_Inorder(root->_left);
		cout << root->_kv.first<<" "<<root->_color<<" ";
		_Inorder(root->_right);
	}
	void Inorder()
	{
		_Inorder(_root);
	}

};

test.cpp

#include"RedBlackTree.h"


int main()
{
	RBTree<int, int> t;
	t.Insert(make_pair(1,1));
	t.Insert(make_pair(8,1));

	t.Insert(make_pair(7,1));
	t.Insert(make_pair(10,1));
	t.Insert(make_pair(-11,1));
	t.Insert(make_pair(-19,1));
	t.Insert(make_pair(-1119,1));
	t.Insert(make_pair(-20,1));
	t.Insert(make_pair(-109,1));
	t.Insert(make_pair(-189,1));
	//t.Insert(make_pair(5,1));
	t.Inorder();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

earthwormer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值