您的位置:首页 > 其它

二叉搜索树-红黑树

2017-11-14 15:14 232 查看
前面介绍了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;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐