红黑树(RBTree)

RBTree

  • [1. 红黑树的概念和性质](#1. 红黑树的概念和性质)
  • [2. 红黑树的实现](#2. 红黑树的实现)
    • [2.1 结点的定义](#2.1 结点的定义)
    • [2.2 插入](#2.2 插入)
    • [2.3 判断红黑树](#2.3 判断红黑树)
    • [2.4 其他接口](#2.4 其他接口)
  • [3. 迭代器](#3. 迭代器)
  • [4. 完整代码](#4. 完整代码)

1. 红黑树的概念和性质

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或

Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。

即:最短路径的长度*2>=最长路径的长度

满足以下几点性质的树为红黑树。

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
    即:每条路径上的黑色结点数目相同

2. 红黑树的实现

2.1 结点的定义

相比普通树的结点,增加了一个父指针,指向父亲。增加了一个常量表示颜色。

cpp 复制代码
template<class K, class V>
struct RBTreeNode
{
	RBTreeNode(const pair<K, V>& kv, Color col = RED)
		:_kv(kv),
		_left(nullptr),
		_right(nullptr),
		_parent(nullptr),
		_col(col)
	{}

	pair<K, V> _kv;
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	Color _col;
};

通过一个pair对象和col构造一个Node,这里存储的数据依旧是键值对的形式。

对于颜色,只有两种。采用枚举的形式。

cpp 复制代码
enum Color
{
	RED,
	BLACK
};

2.2 插入

红黑树是在二叉搜索树的基础上加上平衡条件进行了限制,因此红黑树的插入可分为两步:

  1. 按照二叉搜索的树规则插入新节点
  2. 检测新节点插入后,红黑树的性质是否造到破坏

插入结点时,颜色默认给红色。如果给黑色,会导致某一条路径的黑色结点数增加,就需要修改其他所有路径的黑色结点。如果给红色,可能出现连续的红色结点,也需要修改。但是这个随机的,并不是每次插入都需要修改。

即:颜色为黑色,一定修改。颜色为红色,可能修改。

插入的部分代码

cpp 复制代码
bool Insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv,BLACK); //根结点为黑色
		return true;
	}
	Node* cur = _root;
	Node* parent = _root;
	while (cur)
	{
		if (kv.first > cur->_kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (kv.first < cur->_kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			return false;
		}
	}

	cur = new Node(kv); //默认插入结点为红色

	if (kv.first > parent->_kv.first)
		parent->_right = cur;
	else
		parent->_left = cur;
	cur->_parent = parent;

	while (parent && parent->_col==RED) //出现连续的红色结点
	{
		//...
		//...
	}

	_root->_col = BLACK; // 可能会修改到根节点的颜色

	return true;
}

颜色的修改。

上图中树可以是子树也可以是整棵树。

情况一:只需要将p,u变黑,g变红即可。改变前后两条路径的黑色结点数没有改变。

g如果是根节点,将g变黑。

g如果不是根节点,需要判断g的父节点的颜色,如果为红色,需要继续调整。

情况二:旋转后进行变色

情况二可由情况一转变而来。旋转逻辑和AVL树的中的一致,分为单旋和双旋。只是这里没有了平衡因子。但增加了变色

cpp 复制代码
bool Insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv,BLACK); //根结点为黑色
		return true;
	}
	Node* cur = _root;
	Node* parent = _root;
	while (cur)
	{
		if (kv.first > cur->_kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (kv.first < cur->_kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			return false;
		}
	}

	//new结点并链接
	cur = new Node(kv); //默认插入结点为红色

	if (kv.first > parent->_kv.first)
		parent->_right = cur;
	else
		parent->_left = cur;
	cur->_parent = parent;

	while (parent && parent->_col==RED)
	{
		Node* Pparent = parent->_parent;
		if (parent == Pparent->_left)               
		{                                                   
			Node* uncle = Pparent->_right;
			if (uncle && uncle->_col == RED)  // uncle存在且为红:变色,然后向上继续处理
			{
				uncle->_col = parent->_col = BLACK;
				Pparent->_col = RED;

				cur = Pparent;
				parent = cur->_parent;
			}
			else   // uncle不存在或存在且为黑:旋转+变色处理
			{
				if (cur == parent->_left)   //单旋                    
				{                                      
					RotateRight(Pparent);                            
					parent->_col = BLACK;
					Pparent->_col = RED;
				}
				else                        //双旋       
				{
					RotateLeft(parent);
					RotateRight(Pparent);
					cur->_col = BLACK;
					Pparent->_col = RED;
				}
				break;
			}
		}
		else                                  
		{
			Node* uncle = Pparent->_left;

			if (uncle && uncle->_col == RED)
			{
				uncle->_col = parent->_col = BLACK;
				Pparent->_col = RED;

				cur = Pparent;
				parent = cur->_parent;
			}
			else
			{
				if (cur == parent->_right)
				{
					RotateLeft(Pparent);
					parent->_col = BLACK;
					Pparent->_col = RED;
				}
				else
				{
					RotateRight(parent);
					RotateLeft(Pparent);
					cur->_col = BLACK;
					Pparent->_col = RED;
				}
				break;
			}
		}
	}

	_root->_col = BLACK;
	return true;
}

情况一可能需要向上调整,情况二只需要调整一次。

2.3 判断红黑树

通过红黑树的性质判断,满足四条性质的树为红黑树。

  1. 先计算一条路径的黑色结点,在判断其他路径的黑色结点数是否相等。
  2. 根据存在的父节点和孩子结点的颜色和判断是否有连续的红色结点。
cpp 复制代码
bool IsRBTree()
{
	return _IsRBTree(_root);
}

bool _RBTree(Node* root, int num, int BlackCount)
{
	if (root == nullptr) //一条路径走完后
	{
		if (num == BlackCount)
			return true;
		else
		{
			cout << "两条路径黑色结点个数不同" << endl;
			return false;
		}
	}

	if (root->_col == BLACK)
		num++;
	else
	{
		if (root->_parent && root->_parent->_col == RED)
		{
			cout << "出现连续红色结点" << endl;
			return false;
		}
	}

	return _RBTree(root->_left, num, BlackCount) && _RBTree(root->_right, num, BlackCount);
}

bool _IsRBTree(Node* root)
{
	if (root == nullptr)
		return true;

	if (root->_col == RED)
	{
		cout << "根为红色" << endl;
		return false;
	}

	//统计一条路径中黑色结点的个数
	int count = 0;
	Node* cur = root;
	while (cur)
	{
		if(cur->_col==BLACK) 
			count++;
		cur = cur->_left;
	}
	
	int num = 0;
	return _RBTree(root, num, count);
}

2.4 其他接口

其他接口,包括构造,析构,拷贝等和AVL树类似。

3. 迭代器

容器需要遍历,那么就要实现迭代器。

代码如下,其中,operator++ 的实现比较复杂。

cpp 复制代码
template<class T,class V>
struct RBTreeIterator
{
	typedef RBTreeNode<T,V> Node;
	typedef RBTreeIterator<T,V> Self;

	Node* _node;

	RBTreeIterator(Node* node)
		:_node(node)
	{}

	Self& operator++()
	{
		
	}

	pair<T,V>* operator->()
	{
		return &_node->_kv;
	}

	pair<T, V>& operator*()
	{
		return _node->_kv;
	}

	bool operator!=(const Self& s) const
	{
		return _node != s._node;
	}
	bool operator==(const Self& s) const
	{
		return _node == s._node;
	}

};
cpp 复制代码
Self& operator++()
{
	Node* cur = _node;
	Node* parent = _node->_parent;

	if (cur->_right) //右子树不为空,找右子树的最左结点
	{
		Node* left = cur->_right;
		while (left)
		{
			cur = left;
			left = cur->_left;
		}
		_node = cur;
	}
	else        
	{
		while (parent && cur == parent->_right)
		{
			cur = parent;
			parent = cur->_parent;
		}
		_node = parent;
	}
	
	return *this;
}

测试迭代器和插入

测试红黑树的判断

4. 完整代码

RBTree.h

cpp 复制代码
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

enum Color
{
	RED,
	BLACK
};

template<class K, class V>
struct RBTreeNode
{
	RBTreeNode(const pair<K, V>& kv, Color col = RED)
		:_kv(kv),
		_left(nullptr),
		_right(nullptr),
		_parent(nullptr),
		_col(col)
	{}

	pair<K, V> _kv;
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	Color _col;
};

template<class T,class V>
struct RBTreeIterator
{
	typedef RBTreeNode<T,V> Node;
	typedef RBTreeIterator<T,V> Self;

	Node* _node;

	RBTreeIterator(Node* node)
		:_node(node)
	{}

	Self& operator++()
	{
		Node* cur = _node;
		Node* parent = _node->_parent;

		if (cur->_right) //右子树不为空,找右子树的最左结点
		{
			Node* left = cur->_right;
			while (left)
			{
				cur = left;
				left = cur->_left;
			}
			_node = cur;
		}
		else        
		{
			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		
		return *this;
	}

	pair<T,V>* operator->()
	{
		return &_node->_kv;
	}

	pair<T, V>& operator*()
	{
		return _node->_kv;
	}

	bool operator!=(const Self& s) const
	{
		return _node != s._node;
	}
	bool operator==(const Self& s) const
	{
		return _node == s._node;
	}

};

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

	typedef RBTreeIterator<K, V> Iterator;

	Iterator Begin() //找最左结点
	{
		Node* cur = _root;
		Node* left = cur->_left;
		while (left)
		{
			cur = left;
			left = cur->_left;
		}
		return Iterator(cur);
	}

	Iterator End()
	{
		return Iterator(nullptr);
	}

	RBTree() = default;

	RBTree(const RBTree& a)
	{
		_root = Copy(a._root);
	}

	Node* operator=(RBTree a)
	{
		swap(_root, a._root);
		return _root;
	}


	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv,BLACK); //根结点为黑色
			return true;
		}
		Node* cur = _root;
		Node* parent = _root;
		while (cur)
		{
			if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}

		//new结点并链接
		cur = new Node(kv); //默认插入结点为红色

		if (kv.first > parent->_kv.first)
			parent->_right = cur;
		else
			parent->_left = cur;
		cur->_parent = parent;

		while (parent && parent->_col==RED)
		{
			Node* Pparent = parent->_parent;
			if (parent == Pparent->_left)               //    Pp
			{                                                     //  p         u
				Node* uncle = Pparent->_right;
				if (uncle && uncle->_col == RED)  // uncle存在且为红:变色,然后向上继续处理
				{
					uncle->_col = parent->_col = BLACK;
					Pparent->_col = RED;

					cur = Pparent;
					parent = cur->_parent;
				}
				else											// uncle不存在或存在且为黑:旋转+变色处理
				{
					if (cur == parent->_left)   //单旋       //      Pp                     p
					{                                                    //    p     u    --->     c    Pp
						RotateRight(Pparent);                  // c                                    u
						parent->_col = BLACK;
						Pparent->_col = RED;
					}
					else                                 //双旋       
					{
						RotateLeft(parent);
						RotateRight(Pparent);
						cur->_col = BLACK;
						Pparent->_col = RED;
					}
					break;
				}
			}
			else                                  
			{
				Node* uncle = Pparent->_left;

				if (uncle && uncle->_col == RED)
				{
					uncle->_col = parent->_col = BLACK;
					Pparent->_col = RED;

					cur = Pparent;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)
					{
						RotateLeft(Pparent);
						parent->_col = BLACK;
						Pparent->_col = RED;
					}
					else
					{
						RotateRight(parent);
						RotateLeft(Pparent);
						cur->_col = BLACK;
						Pparent->_col = RED;
					}
					break;
				}
			}
		}

		_root->_col = BLACK;

		return true;
	}

	bool Find(const K& val)
	{
		Node* cur = _root;
		while (cur)
		{
			if (val > cur->_kv.first)
				cur = cur->_right;
			else if (val < cur->_kv.first)
				cur = cur->_left;
			else
				return true;
		}
		return false;
	}

	void Inorder()
	{
		_Inorder(_root);
		cout << endl;
	}

	bool IsRBTree()
	{
		return _IsRBTree(_root);
	}

	int Height()
	{
		return _Height(_root);
	}

	~RBTree()
	{
		Destroy(_root);
		_root = nullptr;
	}

private:

	Node* Copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* newNode = new Node(root->_kv,root->_col);
		newNode->_left = Copy(root->_left);
		newNode->_right = Copy(root->_right);

		if (newNode->_left)
			newNode->_left->_parent = newNode;
		if (newNode->_right)
			newNode->_right->_parent = newNode;

		return newNode;
	}

	void Destroy(Node* root)
	{
		if (root == nullptr)
			return;

		Destroy(root->_left);
		Destroy(root->_right);

		delete root;
		root = nullptr;
	}

	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		int left = _Height(root->_left);
		int right = _Height(root->_right);

		return left > right ? left + 1 : right + 1;
	}

	bool _RBTree(Node* root, int num, int BlackCount)
	{
		if (root == nullptr) //一条路径走完后
		{
			if (num == BlackCount)
				return true;
			else
			{
				cout << "两条路径黑色结点个数不同" << endl;
				return false;
			}
		}

		if (root->_col == BLACK)
			num++;
		else
		{
			if (root->_parent && root->_parent->_col == RED)
			{
				cout << "出现连续红色结点" << endl;
				return false;
			}
		}

		return _RBTree(root->_left, num, BlackCount) && _RBTree(root->_right, num, BlackCount);
	}

	bool _IsRBTree(Node* root)
	{
		if (root == nullptr)
			return true;

		if (root->_col == RED)
		{
			cout << "根为红色" << endl;
			return false;
		}

		//统计一条路径中黑色结点的个数
		int count = 0;
		Node* cur = root;
		while (cur)
		{
			if(cur->_col==BLACK) 
				count++;
			cur = cur->_left;
		}
		
		int num = 0;
		return _RBTree(root, num, count);
	}

	void RotateLeft(Node* parent)
	{
		Node* Pparent = parent->_parent;
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		subR->_left = parent;

		parent->_parent = subR;
		subR->_parent = Pparent;

		if (subRL)
			subRL->_parent = parent;

		if (Pparent == nullptr) //说明parent结点为原来的根
			_root = subR;
		else
		{
			if (Pparent->_left == parent)
				Pparent->_left = subR;
			else
				Pparent->_right = subR;
		}
	}

	void RotateRight(Node* parent)
	{
		Node* Pparent = parent->_parent;
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		subL->_right = parent;

		parent->_parent = subL;
		subL->_parent = Pparent;

		if (subLR)
			subLR->_parent = parent;

		if (Pparent == nullptr)
			_root = subL;
		else
		{
			if (Pparent->_left == parent)
				Pparent->_left = subL;
			else
				Pparent->_right = subL;
		}
	}

	void _Inorder(Node* root)
	{
		if (root == nullptr)
			return;
		_Inorder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_Inorder(root->_right);
	}

private:
	Node* _root = nullptr;
};

test.cpp

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include"RBTree.h"


void TestRBTree()
{
	RBTree<int, int> r;
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	for (auto val : a)
	{
		r.Insert({ val,val });
		//cout << r.IsRBTree()<<endl<<endl;
	}

	r.Inorder();
	cout << r.IsRBTree() << endl;
	cout << r.Height() << endl;

	RBTree<int, int> r1(r);  /拷贝构造
	RBTree<int, int> r2;

	r2 = r;   //赋值

	cout << endl;


}

void TestRBTree1()
{
	RBTree<int, int> r;
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	for (auto val : a)
	{
		r.Insert({ val,val });
	}

	RBTree<int, int>::Iterator it = r.Begin();
	while (it != r.End())
	{
		cout << it->first << " ";
		cout << (*it).first << " ";
		++it;
	}

}
int main()
{
	TestRBTree();
	//TestRBTree1();
	return 0;
}
相关推荐
小俊俊的博客1 小时前
海康RGBD相机使用C++和Opencv采集图像记录
c++·opencv·海康·rgbd相机
_WndProc1 小时前
C++ 日志输出
开发语言·c++·算法
薄荷故人_1 小时前
从零开始的C++之旅——红黑树及其实现
数据结构·c++
m0_748240021 小时前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome
qq_433554542 小时前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++
努力学习编程的伍大侠2 小时前
基础排序算法
数据结构·c++·算法
yuyanjingtao2 小时前
CCF-GESP 等级考试 2023年9月认证C++四级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
闻缺陷则喜何志丹3 小时前
【C++动态规划 图论】3243. 新增道路查询后的最短距离 I|1567
c++·算法·动态规划·力扣·图论·最短路·路径
charlie1145141913 小时前
C++ STL CookBook
开发语言·c++·stl·c++20
小林熬夜学编程3 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http