红黑树的由来
红黑树是由美国计算机科学家Rudolf Bayer和Edward M. McCreight于1972年发明的(最初被称为"对称二叉B-树")。然而,它的命名则是由后来的研究者Leonidas J. Guibas和Robert Sedgewick于1978年提出的,他们使用"红黑树"这个术语来描述该数据结构的特性。
红黑树与AVL树
之前说过AVL树,AVL树是一种严格平衡的二叉搜索树,红黑树它规定最长路径不能超过最短路径的两倍,所以红黑树是一种近似平衡的二叉搜索树。
而红黑树的应用十分广泛,相比之下AVL树的应用要少的多。
原因:
1.它相比AVL树更好控制。
2.当插入的数据(非有序)足够大时,虽然红黑树的高度会比AVL树要高,但是由于它们的查找效率都是logn级别的,实际查找效率相差很小,反而AVL树的旋转次数要比红黑树多很多,所以综合性能上红黑树要略高与AVL树。
另外旋转操作其实是二叉搜索树的操作,它同样适用与红黑树。
红黑树的性质
1.每个结点不是红就是黑色。
2.根结点必须是黑色的。
3.如果一个结点是红色的,那么它的孩子必须是黑色的(不能有连续的红结点)
4.对于每个结点,从该结点到叶子结点的路径上,黑结点的数量必须是一样的。
5.叶子结点是黑结点(此处的叶子结点指的是空结点)
6.最短路径的长度不能超过最短路径长度的两倍。
违反了以上性质说明该树不是合法的红黑树。
红黑树的插入及旋转
首先新插入的结点必须是红色。(根结点除外)
在插入结点后需要通过以下操作来维护红黑树:
1.如果parent存在且parent为红。(违反了不能有连续的红结点的规则)
首先需要找到uncle结点,及parent的兄弟结点,简称u。
1.1如果u存在,且u为红色。
Node* uncle = grandfather->_right;
//情况一:u存在且u为红色,那么要将u改黑,并且修改cur和parent继续调整。
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;//
cur = grandfather;
parent = cur->_parent;
}
1.2如果u不存在或者u为黑
此时就需要对树进行旋转+变色。并且又可能会出现单旋或者双旋。
else//情况二:u不存在或者u为黑
{
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
}
这里对与颜色的更新其实比AVL树要简单。
红黑树的调试
和AVL树一样,一旦树出现了问题,手动一个一个测试很困难,我们同样可以借助程序帮我们快速定位问题
bool IsBalance()
{
return IsBalance(_root);
}
bool IsBalance(Node* root)
{
if (root == nullptr) return true;
if (root->_col == RED)
{
cout << root->_kv.first << "头部颜色错误" << endl;
return false;
}
int benchmark = 0;
Node* cur = root;
while (cur)
{
if (cur->_col == BLACK) benchmark++;
cur = cur->_left;
}
return CheckColour(root, 0, benchmark);
}
bool CheckColour(Node* root, int blacknum, int benchmark)
{
if (root == nullptr)
{
if (blacknum != benchmark)
{
cout << "路径长度错误" << endl;
return false;
}
return true;
}
if (root->_col == BLACK) blacknum++;
if (root->_col == RED && root->_parent->_col == RED)
{
cout << root->_kv.first << "出现了连续的红色结点" << endl;
return false;
}
return CheckColour(root->_left, blacknum, benchmark) && CheckColour(root-
>_right, blacknum, benchmark);
}
int Height()
{
return Height(_root);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = Height(root->_left);
int rightHeight = Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
完整代码实现
#pragma once
namespace hzj
{
enum Colour
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _col(RED)
{}
};
template <class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv)
{
//第一次插入
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)//找到插入位置,记得记录parent
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(kv);
cur->_col = RED;//红黑树新插入的结点的颜色为红色
//链接新节点
if (cur->_kv.first < parent->_kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//不能有连续的红节点,如果父亲是红结点,那么需要分情况调整
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)//parent在grandfather左边。
{
//那么此时u在grand的右边
Node* uncle = grandfather->_right;
//情况一:u存在且u为红色,那么要将u改黑,并且修改cur和parent继续调整。
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;//
cur = grandfather;
parent = cur->_parent;
}
else//情况二:u不存在或者u为黑
{
if (cur == parent->_left)
{
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
bool IsBalance()
{
return IsBalance(_root);
}
bool IsBalance(Node* root)
{
if (root == nullptr) return true;
if (root->_col == RED)
{
cout << root->_kv.first << "头部颜色错误" << endl;
return false;
}
int benchmark = 0;
Node* cur = root;
while (cur)
{
if (cur->_col == BLACK) benchmark++;
cur = cur->_left;
}
return CheckColour(root, 0, benchmark);
}
int Height()
{
return Height(_root);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = Height(root->_left);
int rightHeight = Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
bool CheckColour(Node* root, int blacknum, int benchmark)
{
if (root == nullptr)
{
if (blacknum != benchmark)
{
cout << "路径长度错误" << endl;
return false;
}
return true;
}
if (root->_col == BLACK) blacknum++;
if (root->_col == RED && root->_parent->_col == RED)
{
cout << root->_kv.first << "出现了连续的红色结点" << endl;
return false;
}
return CheckColour(root->_left, blacknum, benchmark) && CheckColour(root->_right, blacknum, benchmark);
}
private:
void RotateL(Node* parent)
{
Node* cur = parent->_right;
Node* curleft = cur->_left;
parent->_right = curleft;
if (curleft)
{
curleft->_parent = parent;
}
cur->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = cur;
if (parent == _root)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}
void RotateR(Node* parent)
{
Node* cur = parent->_left;
Node* curright = cur->_right;
parent->_left = curright;
if (curright)
curright->_parent = parent;
Node* ppnode = parent->_parent;
cur->_right = parent;
parent->_parent = cur;
if (ppnode == nullptr)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}
Node* _root = nullptr;
};
void test1()
{
/*const int N = 4;
vector<int> v;
v.reserve(N);
srand(time(0));*/
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
/*for (size_t i = 0; i < N; i++)
{
v.push_back(i);
}*/
RBTree<int, int> rbt;
for (auto e : a)
{
if (e == 26)
{
int x = 0;
}
rbt.Insert(make_pair(e, e));
//cout << "Insert:" << e << "->" << t.IsBalance() << endl;
}
cout << rbt.IsBalance() << endl;
//cout << rbt.Height() << endl;
}
}