前面介绍了AVL树,虽然AVL树将二叉树的高度差保证在1,但是实现的太过复杂,因为要不断调整平衡因子。故而要来介绍另外一个用途比较广的结构-红黑树。
红黑树
先来看来红黑树的特性:
1、每个节点非红即黑
2、根节点为黑色
3、不能有连续的红节点
4、每条路径上的黑色节点数相等
5、空节点为黑色
先来想一个问题,红黑树的定义保证它最长路径不会超过最短路径的二倍,那么来想想为什么?
节点的结构
因为搜索结构在实际运用当中都是采用这种Key,Value模型,所以这里就先这样实现,后面对RBTree进行封装时,会做一些小的调整。
enum COLOUR{RED,BLACK};
template <class K,class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;//因为要涉及到调平衡,所以定义为三叉链
K _key;
V _value;
COLOUR _colour;//枚举类型的颜色属性,每一个节点非红即黑
};
插入
基本的插入和之前的普通搜索树,AVL树都是一样的,先找到待插入位置,然后进行插入即可,主要的不同就是在动态调整。
至于旋转的过程,红黑树和AVL树都是一样的。
插入时需要注意的是,第四条规则:每条路径上的黑色节点数相等,所以我们可以在初始化节点的时候直接默认是红色的节点,这样就可以避免冲突这条规则。
下面这段代码在实现普通搜索树,AVL树,红黑树都是一样的。
if (_root == NULL)//先判断空树的场景
{
Node* _root = new Node(key, value);
_root->_colour = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
if (key < cur->_key)
{
parent = cur->_parent;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
{
assert(false);
}
}
//走到这里,找到待插入点
cur = new Node(key, value);
if (key < cur->_key)
{
parent->_left = cur;
cur->_parent = parent;
}
else if (key > cur->_key)
{
parent->_right = cur;
cur->_parent = parent;
}
//走到这里说明节点插入进入了,核心的思想就是下面要进行的动态调整
动态调整
下面图示中cur代表当前节点,parent/p代表父节点,uncle/u代表叔叔节点,grandfather/g代表祖父节点。
一共分三种情况:
一:叔叔存在且为红
如果是这种情况,直接将父节点和叔叔节点置为红色,也不需要进行旋转,至于为什么将祖父节点置为红色?
1、当前节点的祖父节点是根节点(程序的最后直接将整棵树的根置黑)
2、当前节点的祖父节点不是根
讨论不是根,如图:
二:叔叔不存在/存在为黑(cur为p的左)
这里的叔叔只要不是存在且为红,就不影响旋转。
以p为根进行一次右单旋(镜像式的左旋类似),然后将p置为黑,g置为红
,因为以g为根的子树上的路径黑色节点个数并没有增加,故不用将旋转后的p在置为红继续向上调整。
三:叔叔不存在/存在为黑(cur为p的右)
仔细想一下,这里的第三种是先左旋转化为第二种,再进行左旋后,当前节点的cur和parent对应到第二种的结构中刚好是相反的,所以再进行左旋前/后,要将cur和parent两个节点进行swap,才能转化为第二种结构进行处理。
整个调整过程应该是一个循环来控制:
while(parent && parent->_color == RED);
再进行完动态调整后,最后直接了当将整棵树的根节点变为黑色,从而满足第一条性质。
如果对于旋转部分还不太了解可以先了解AVL树的实现部分,两部分的旋转逻辑一模一样
附上整个简单实现的代码:
#pragma once
#include<iostream>
#include<assert.h>
enum COLOUR{RED,BLACK};
template <class K,class V>
struct RBTreeNode
{
RBTreeNode(const K& key, const V& value)
: _left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
, _colour(RED)
{}
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
K _key;
V _value;
COLOUR _colour;
};
template <class K,class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
: _root(NULL)
{}
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
Node* _root = new Node(key, value);
_root->_colour = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
if (key < cur->_key)
{
parent = cur->_parent;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
{
assert(false);
}
}
//走到这里,找到待插入点
cur = new Node(key, value);
if (key < cur->_key)
{
parent->_left = cur;
cur->_parent = parent;
}
else if (key > cur->_key)
{
parent->_right = cur;
cur->_parent = parent;
}
//动态调整节点
while (parent && parent->_colour == RED )
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_colour == RED)
{
parent->_colour = uncle->_colour = BLACK;
grandfather->_colour = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
//BUG 第一次旋转后改变了parent和cur的位置,导致第二次旋转后颜色设置错误
std::swap(parent, cur);
RotateL(parent);
}
RotateR(grandfather);
grandfather->_colour = RED;
parent->_colour = BLACK;
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_colour == RED)
{
parent->_colour = uncle->_colour = BLACK;
grandfather->_colour = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
std::swap(parent, cur);
RotateR(parent);
}
RotateL(grandfather);
grandfather->_colour = RED;
parent->_colour = BLACK;
break;
}
}
}
_root->_colour = BLACK;
return true;
}
bool CheckBalance()
{
size_t k = 0;
if (NULL == _root)
return true;
if (RED == _root->_colour)
{
std::cout << "根节点为红" << " ";
return false;
}
size_t BlankCount = 0;
Node* cur = _root;
while (cur)
{
if (BLACK == cur->_colour)
{
BlankCount++;
cur = cur->_left;
}
}
_CheckBalance(_root,BlankCount,k);
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_right;
Node* pparent = parent->_parent;
parent->_right = subR->_left;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
parent->_parent = subR;
while (NULL == pparent)
{
_root = subR;
subR->_parent = NULL;
}
if (parent == pparent->_left)
pparent->_left = subR;
else if (parent == pparent->_right)
pparent->_right = subR;
subR->_parent = pparent;
parent = subR;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* pparent = parent->_parent;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
parent->_parent = subL;
while (NULL == pparent)
{
_root = subL;
subL->_parent = NULL;
}
if (parent == pparent->_left)
parent->_left = subL;
else if (parent == pparent->_right)
parent->_right = subL;
subL->_parent = pparent;
parent = subL;
}
bool _CheckBalance(Node* root, size_t BlankCount, size_t k)
{
if (NULL == root)
return true;
if (BLACK == root->_colour)
k++;
Node* parent = root->_parent;
if (root->_colour == RED && parent->_colour == RED)
{
std::cout << "相邻的红节点" << " ";
return false;
}
if (root->_left == NULL && root->_right == NULL)
{
if (k != BlankCount)
{
std::cout << "黑色数量不相等" << " ";
return false;
}
return true;
}
return (_CheckBalance(root->_left, BlankCount, k) && _CheckBalance(root->_right, BlankCount, k));
}
private:
Node* _root;
};