红黑树的概念和性质
概念:红黑树是一棵二叉搜索树,它在以前的搜索二叉树的基础上每个节点上增加了一个存储位来表示节点的颜色,可以是红的或黑的。通过对任何一条从根到叶子简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似于平衡。
红黑树的性质:
1. 每个节点,不是红色就是黑色的
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个子节点是黑色的 。即不存在两个相连的红色节点
4. 每条路径上有相同数量的黑色节点
为什么红黑树能保证最长路径不超过最短路径的两倍?
红黑树满足上面的四个性质。当一棵树全部是黑节点时,满足上面的所有性质:
比如:
在满足上面的性质情况下,可以增加红节点。
比如:
如图,最短路径就是为全黑节点,最长路径为加了红节点的那条路径。在最短路径不能再减少黑色节点了,否则就不满足第四条性质,每条路径有相同的黑色节点。而最长路径也不能再增加节点,如果加红节点,就会出现相连的红色节点;如果增加黑色节点,每条路径的黑色节点将不会相同。
可知,最长路径的节点数不会超过最短路径的节点数的两倍。
有了AVL树(高度平衡),为什么还要有红黑树
AVL树高度平衡树,增删查改的时间复杂度O((Log2)N)(log以2为底N的对数)
红黑树是最长路径不超过最短路径的2倍,在最坏的情况下,时间复杂度为O(2Log2(N))(2倍的log以2为底N的对数)。
对于计算机来说,O((Log2)N)和O(2Log2(N))效率差不多。相对而言,降低了旋转的要求,所以性能会优于AVL树,所以有了红黑树的出现,而且实际运用中红黑树更多。
比如:
1. C++ STL库 – map
2. Java 库
3. linux内核
4. 其他一些库
红黑树的插入
为了满足那4条性质,在插入时,如果为空树,就插入黑节点;只要有节点,再插入时,插入的都是红节点,因为上面三条性质中,最难保持的就是每条路径的黑色节点数相同,所以在插入时尽量满足第四条性质,而去打破第三条。然后再进行调整节点的颜色。
插入分为三种情况:
第一种情况:cur为红色,parent为黑色,grandfather为黑色uncle存在且为黑色(parent和uncle可以互换位置)
cur是新插入的节点,则a,b,c,d,e都将不存在,cur还有可能就是子树的grandfather变色而来的。
如:
这时将节点进行变色,使该树继续满足红黑树的性质,将parent和uncle的颜色变为黑色,grandfather变为红色。
第二种情况:cur为红色且为parent的左孩子,parent为红色grandfather为黑色,uncle不存在或uncle为黑色
uncle不存在时,cur为新插节点,a,b,c,d,e都不存在
uncle存在时,cur是第一种情况调过来的,a,b,c,为红节点,d,e为黑节点。
然后以parent进行右旋,将parent变为黑色,grandfather变为红色
当parent为grandfather的右孩子,cur为parent的右孩子时,以grandfather进行左旋,一样的变色。
第三种情况:cur为红色且为parent的左孩子,parent为红色,grandfather为黑色,uncle不存在或uncle为黑色
uncle不存在时,cur为新插节点,a,b,c,d,e都不存在
uncle存在时,cur是第一种情况调过来的,a,b,c,为红节点,d,e为黑节点。
先以parent进行左旋,旋转后交换parent和cur
再以grandfather进行右旋,将parent变为黑色,grandfather变为红色
当parent为grandfather的右孩子,cur为parent的左孩子时,以parent进行右旋后交换,再以grandfather进行左旋,一样的变色。
代码:
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
_root->_color = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
//找插入的位置
while (cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
return false;
}
cur = new Node(key, value);
if (key < parent->_key)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
while (parent && parent->_color == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)//parent为左孩子
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_color == RED)
{
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else//uncle不存在或uncle存在且为黑色
{
//uncle不存在,cur为新插节点。uncle存在,cur为上面的if调过来的,
//就是相当于if中的grandfather
if (cur == parent->_right)
{
RotateL(parent);
swap(cur, parent);
}
RotateR(grandfather);
parent->_color = BLACK;
grandfather->_color = RED;
break;
}
}
else//parent==grandfather->_right
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_color == RED)
{
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else//uncle不存在或uncle存在且为黑
{
if (cur == parent->_left)
{
RotateR(parent);
swap(cur, parent);
}
RotateL(grandfather);
parent->_color = BLACK;
grandfather->_color = RED;
break;
}
}
_root->_color = BLACK;
}
return true;
}
红黑树的查找和删除
红黑树的查找和搜索二叉数类似
红黑树的删除和搜索二叉树的类似,不同的是要进行调整红黑节点,使删除后还是红黑树
判断是不是一棵红黑树
就是看一棵搜索二叉树是不是满足红黑树的性质:
1、根节点是不是黑的,是黑的继续向下判断,是红的就直接返回,不是红黑树
2、找父子节点有没有相连的红节点
3、先找了最左路径的黑节点的个数,与其他路径的黑节点进行比较,用递归实现,只要有不相同的黑色节点,就不是红黑树。
代码:
bool IsRBTree()
{
if (_root == NULL)//空树,算是红黑树
return true;
if (_root->_color == RED)//根节点为红色,不是红黑树
return false;
Node* cur = _root;
size_t BlackNum = 0;
while (cur)
{
if (cur->_color == BLACK)
++BlackNum;
cur = cur->_left;
}
int num = 0;
return _IsRBTree(_root, BlackNum, num);
}
bool _IsRBTree(Node* cur, const int& BlackNum, int num)
{
if (cur == NULL)
{
if (BlackNum != num)
{
cout << "黑色节点不相同" << endl;
return false;
}
return true;
}
//有两个连续的红节点,不是红黑树,直接返回
if (cur->_parent && cur->_parent->_color == RED && cur->_color == RED)
return false;
if (cur->_color == BLACK)
num++;
return _IsRBTree(cur->_left, BlackNum, num) && _IsRBTree(cur->_left, BlackNum, num);
}
红黑树的左右旋
左单旋和右单旋原理与AVL树相同,不同的是AVL树调整平衡因子,红黑树调整红黑节点。
代码:
void RotateL(Node* parent)//左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (ppNode == NULL)
{
_root = subR;
subR->_parent = NULL;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
void RotateR(Node* parent)//右单旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (ppNode == NULL)
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
整体代码:
"RBTree.h"
#pragma once
enum Color
{
RED,
BLACK,
};
template<class K,class V>
struct RBTreeNode
{
K _key;
V _value;
Color _color;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
RBTreeNode(const K& key,const V& value)
:_key(key)
, _value(value)
, _color(RED)
, _left(NULL)
, _right(NULL)
, _parent(NULL)
{}
};
template <class K,class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_root(NULL)
{}
~RBTree()
{
_Destroy(_root);
}
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
_root->_color = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
//找插入的位置
while (cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
return false;
}
cur = new Node(key, value);
if (key < parent->_key)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
while (parent && parent->_color == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)//parent为左孩子
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_color == RED)
{
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else//uncle不存在或uncle存在且为黑色
{
//uncle不存在,cur为新插节点。uncle存在,cur为上面的if调过来的,
//就是相当于if中的grandfather
if (cur == parent->_right)
{
RotateL(parent);
swap(cur, parent);
}
RotateR(grandfather);
parent->_color = BLACK;
grandfather->_color = RED;
break;
}
}
else//parent==grandfather->_right
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_color == RED)
{
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else//uncle不存在或uncle存在且为黑
{
if (cur == parent->_left)
{
RotateR(parent);
swap(cur, parent);
}
RotateL(grandfather);
parent->_color = BLACK;
grandfather->_color = RED;
break;
}
}
_root->_color = BLACK;
}
return true;
}
bool IsRBTree()
{
if (_root == NULL)//空树,算是红黑树
return true;
if (_root->_color == RED)//根节点为红色,不是红黑树
return false;
Node* cur = _root;
size_t BlackNum = 0;
while (cur)
{
if (cur->_color == BLACK)
++BlackNum;
cur = cur->_left;
}
int num = 0;
return _IsRBTree(_root, BlackNum, num);
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (ppNode == NULL)
{
_root = subR;
subR->_parent = NULL;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (ppNode == NULL)
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
protected:
void _Destroy(Node* cur)
{
if (cur == NULL)
return;
_Destroy(cur->_left);
_Destroy(cur->_right);
delete cur;
cur = NULL;
}
bool _IsRBTree(Node* cur, const int& BlackNum, int num)
{
if (cur == NULL)
{
if (BlackNum != num)
{
cout << "黑色节点不相同" << endl;
return false;
}
return true;
}
//有两个连续的红节点,不是红黑树,直接返回
if (cur->_parent && cur->_parent->_color == RED && cur->_color == RED)
return false;
if (cur->_color == BLACK)
num++;
return _IsRBTree(cur->_left, BlackNum, num) && _IsRBTree(cur->_left, BlackNum, num);
}
void _InOrder(Node* cur)
{
if (cur == NULL)
return;
_InOrder(cur->_left);
cout << cur->_key << " ";
_InOrder(cur->_right);
}
protected:
Node* _root;
};
void TestRBTree()
{
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
RBTree<int, int> rb;
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
rb.Insert(a[i], i);
//cout << a[i] <<"IsRBTree?" << rb.IsRBTree() << endl;
}
rb.InOrder();
cout << "IsRBTree?" << rb.IsRBTree() << endl;
}
"Test.cpp"
#include <iostream>
using namespace std;
#include "RBTree.h"
int main()
{
TestRBTree();
return 0;
}