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>=最长路径的长度
满足以下几点性质的树为红黑树。
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
即:每条路径上的黑色结点数目相同
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 插入
红黑树是在二叉搜索树的基础上加上平衡条件进行了限制,因此红黑树的插入可分为两步:
- 按照二叉搜索的树规则插入新节点
- 检测新节点插入后,红黑树的性质是否造到破坏
插入结点时,颜色默认给红色。如果给黑色,会导致某一条路径的黑色结点数增加,就需要修改其他所有路径的黑色结点。如果给红色,可能出现连续的红色结点,也需要修改。但是这个随机的,并不是每次插入都需要修改。
即:颜色为黑色,一定修改。颜色为红色,可能修改。
插入的部分代码
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 判断红黑树
通过红黑树的性质判断,满足四条性质的树为红黑树。
- 先计算一条路径的黑色结点,在判断其他路径的黑色结点数是否相等。
- 根据存在的父节点和孩子结点的颜色和判断是否有连续的红色结点。
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;
}