一、概念
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结
点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点上
的简单路径来约束,红黑树保证最长路径不超过最短路径的两倍,因而近视
平衡。
二、性质
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个根节点是红色的,则它的两个叶子结点是黑色的(没有两个连续
的红色结点)
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相
同数目的黑色结点(每条路径上黑色结点的数量相等)
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
思考:
为什么满足上面的颜色约束性质,红黑树能保证最长路径不超过最短路径的两
倍?
三、插入实现
注意:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
【情况一】
cur为红,p为红,g为黑,u存在且为红
则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
【情况二】
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur
为p的右孩子,则进行左单旋转
p、g变色--p变黑,g变红
【情况三】
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相
反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
则转换成了情况2
四、源码实现:
RBTree.h
#pragma once
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
enum Color
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode(const K& key, const V& value, Color color = RED)
:_value(value)
, _key(key)
, _pLeft(NULL)
, _pRight(NULL)
, _pParent(NULL)
, _color(color)
{}
V _value;
K _key;
RBTreeNode<K, V>* _pLeft;
RBTreeNode<K, V>* _pRight;
RBTreeNode<K, V>* _pParent;
Color _color; //节点的颜色
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_pHead(NULL)
{
_pHead = new Node(0, 0);
_pHead->_pLeft = _pHead;
_pHead->_pRight = _pHead;
}
Node *GetMaxNode()
{
Node* pCur = GetRoot();
while (pCur->_pRight)
pCur = pCur->_pRight;
return pCur;
}
Node *GetMinNode()
{
Node* pCur = GetRoot();
while (pCur->_pLeft)
pCur = pCur->_pLeft;
return pCur;
}
bool Insert(const K& key, const V& value)
{
Node*& pRoot = GetRoot();
if (pRoot == NULL) // 当一个节点也没有时
{
pRoot = new Node(key, value);
pRoot->_color = BLACK;
pRoot->_pParent = _pHead;
return true;
}
Node* pCur = pRoot;
Node* pParent = NULL;
while (pCur)
{
if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (key == pCur->_key)//若已存在,返回false
{
return false;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
pCur = new Node(key, value);
if (key < pParent->_key)
{
pParent->_pLeft = pCur;
pCur->_pParent = pParent;
}
else
{
pParent->_pRight = pCur;
pCur->_pParent = pParent;
}
//调整颜色
while (pCur != pRoot && pParent->_color == RED)
{
Node* garndFather = pParent->_pParent;
Node* uncle = NULL;
if (pParent == garndFather->_pRight)
{
uncle = garndFather->_pLeft;
}
else
uncle = garndFather->_pRight;
if (uncle != NULL&&uncle->_color == RED)
{
pParent->_color = BLACK;
uncle->_color = BLACK;
garndFather->_color = RED;
}
else //uncle不存在或uncle为黑
{
if (pParent == garndFather->_pLeft) //父亲是爷爷的左孩子
{
if (pCur = pParent->_pRight)
{
RotateLeft(pParent);
swap(pParent, pCur);
}
if (pCur = pParent->_pLeft)
{
RotateRight(garndFather);
pParent->_color = BLACK;
garndFather->_color = RED;
}
}
else //父亲是爷爷的右孩子
{
if (pCur = pParent->_pLeft)
{
RotateRight(pParent);
swap(pParent, pCur);
}
if (pCur = pParent->_pRight)
{
RotateLeft(garndFather);
pParent->_color = BLACK;
garndFather->_color = RED;
}
}
}
pCur = garndFather;
pParent = pCur->_pParent;
}
_pHead->_pLeft = GetMinNode();
_pHead->_pRight = GetMaxNode();
pRoot->_color = BLACK;
return true;
}
void RotateLeft(Node* parent)
{
Node* pparent = parent->_pParent;
Node* subR = parent->_pRight;
Node* subRL = subR->_pLeft;
if (pparent == _pHead)
{
Node*& pRoot = GetRoot();
pRoot = subR;
}
else
{
if (parent == pparent->_pLeft)
{
pparent->_pLeft = subR;
}
else
{
pparent->_pRight = subR;
}
}
subR->_pParent = pparent;
parent->_pParent = subR;
parent->_pRight = subRL;
if (subRL != NULL)
{
subRL->_pParent = parent;
}
}
void RotateRight(Node* parent)
{
Node* subL = parent->_pLeft;
Node* subLR = subL->_pRight;
Node* pparent = parent->_pParent;
if (pparent == _pHead)
{
Node*& pRoot = GetRoot();
pRoot = subL;
}
else
{
if (parent = pparent->_pLeft)
{
pparent->_pLeft = subL;
}
else
{
pparent->_pRight = subL;
}
}
subL->_pParent = pparent;
subL->_pRight = parent;
parent->_pParent = subL;
parent->_pLeft = subLR;
if (subLR != NULL)
{
subLR->_pParent = parent;
}
}
void InOrder()
{
Node*& pRoot = GetRoot();
_InOrder(pRoot);
}
void _InOrder(Node* pRoot)
{
if (pRoot)
{
_InOrder(pRoot->_pLeft);
cout << pRoot->_key << " ";
_InOrder(pRoot->_pRight);
}
}
bool CheckRBTree()
{
Node*& pRoot = GetRoot();
if (pRoot == NULL)
{
return true;
}
if (pRoot->_color == RED)
{
return false;
}
//找到一条路径上黑色节点的个数
size_t blackCount = 0;
Node* pCur = pRoot;
while (pCur)
{
if (pCur->_color == BLACK)
{
blackCount++;
}
pCur = pCur->_pLeft;
}
size_t k = 0;
return _CheckRBTree(pRoot, blackCount, k);
}
//每一条路径上的黑色节点相同时才是红黑树
bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)//k一定为值传递
{
if (pRoot == NULL)
{
return true;
}
//当出现两个连续的红色节点的时候,可以确定不是红黑树
if (pRoot->_pParent&&pRoot->_color == RED&&pRoot->_pParent->_color == RED)
{
return false;
}
//若是黑节点,k++
if (pRoot->_color == BLACK)
{
k++;
}
//若是叶子节点,判断k和blackCount是否相等
if (pRoot->_pLeft == NULL&&pRoot->_pRight == NULL)
{
if (k != blackCount)
{
return false;
}
}
return _CheckRBTree(pRoot->_pLeft, blackCount, k);
}
private:
Node* _pHead; //红黑树加上一个头结点进行迭代器操作
//(头结点的左孩子指向红黑树的最小值,右孩子指向最大值,parent域指向根节点)
private:
Node* & GetRoot()
{
return _pHead->_pParent;
}
};
RBTree.cpp
#include"RBTree.h"
void Test()
{
int a[] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
RBTree<int, int> bt;
for (size_t idx = 0; idx < sizeof(a) / sizeof(a[0]); ++idx)
{
bt.Insert(a[idx], a[idx]);
}
bt.InOrder();
cout << endl;
cout << bt.CheckRBTree() << endl;
}
int main()
{
Test();
system("pause");
return 0;
}
五、红黑树和AVL树的比较
红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是
O(lg(N))
红黑树的不追求完全平衡,保证最长路径不超过最短路径的2倍,相对而
言,降低了旋转的要求,所以性能跟AVL树差不多,但是红黑树实现更简
单,所以实际运用中红黑树更多。