看红黑树之前先看AVL树有很多相似的地方,我也写了一篇AVL树的总结,我就没重复总结了。
我们先看红黑树特性
1.根节点是黑色
2.每个节点只能是黑色或者红色
3.如果一个节点是红色,它得子节点必须是黑色的。
4.每个叶子节点(NIL)是黑色的,这里可以是所有叶子节点连着最后一个(黑色的)哨兵节点(为NULL)。
5.从任意一个节点到其叶子节点的所有路径中,包含相同数目的黑色的节点。(不能从父节点回退)
看一下红黑树的长相
红黑树的高度问题
由于它的特性所影响,从根节点出发,整个红黑树的最长路径(树的高度)不会超过最短路径的2倍。看张图就知道了
看完图也可以看一下推导思路
一棵含n个结点的红黑树最大的高度不超过2log(n+1)。我简单说下思路
(1)我们先假设该定理成立 推导出 h <= 2log(n+1) 再推导得 n > 2 ^(h/2) -1 (^ 是平方的意思)
(2)上面推导出 一棵高度为h 的红黑树它至少 有 n 个节点
(3) 我们设任意节点到该叶子节点的黑结点个数为B(hx)。特性3 红色节点子节点必须是黑色的。得出一棵树的高度的 B(hx) >=h/2。原因有以下几点。
结点只能为黑或者红。红节点子节点为黑。
意味着一条路径有一个红就会有一个黑节点。
从任意一个节点到其叶子节点得所有路径中,包含相同数目的黑色节点。意味着黑色节点数目唯一性。
而树的高度。便是最长路径的节点的个数,推出 该路径的 "黑节点个数" >= h/2 也就是 B(hx) >= h/2
(4) 根据两个公式 n >= 2^(h/2)-1 和 B(hx) >=h/2 推出 n >= 2^(B(hx)-1
(5)数学归纳法过程
红黑树高度 = 0 带入公式 n>= 2^B(hx)-1 0>= 0成立
红黑树高度为 h-1 黑节点个数 为 B(hx) (从红节点开始) 或者B(hx)-1 (从黑节点开始)
我们要证明高度为h 至少含多少个内节点 。这时候就要取高度h-1 黑节点小的时候。
n > = (2^(B(hx)-1) -1) + (2^(B(hx)-1 )-1) +1 (这种情况是从黑节点开始的,所以+1)
n>= (2^(B(hx)-1)
再看一下红黑树的结构体
Color Type 是枚举类型 说明它的性质非红即黑。(不要和我说没颜色)
Nil 是一个哨兵位
typedef int KeyType;
typedef enum {RED = 0, BLACK = 1} ColorType;
typedef struct rb_node
{
rb_node *leftchild;
rb_node *parent;
rb_node *rightchild;
ColorType color; //
KeyType key;
}rb_node;
typedef struct //头节点head
{
rb_node *head;
rb_node *Nil;
int cursize;
}RBTree;
平衡二叉树和红黑树的区别
(1) 平衡二叉树和红黑树都是通过特性来控制树的高度
平衡二叉树控制平衡相对比较严格,左子树高度和右子树的高度差不能超过1。
而红黑树是通过特性和颜色来相对控制其平衡
(2)平衡二叉树插入新节点时候,效率会低很多,红黑树则效率快一些
我们分析一下几种插入情况插入时候,(新插入节点是红色,但是他的颜色在双旋之后是可以变黑的。这个颜色不能随着旋转之类的变掉颜色)
新节点一定是红色,插入进去,父节点是黑色,皆大欢喜,我直接插入,不要调整
但是如果是父节点为红色
我们画个图
第一种情况
叔叔爸爸都为红,就把爷爷染红,叔叔爸爸染黑
第二种情况
叔叔为爷爷的左孩子且为黑色节点,父亲节点为红色,这时候就需要左旋或者双旋
看图
第三种情况
叔叔为右节点且为黑色,父亲为红色,可能要右旋或者双旋。
这个是核心代码你看下
//pa为新节点的父节点
void Insert_Item(RBTree *ptree,rb_node *pa,KeyType kx)
{
rb_node *s = Buynode(pa,RED); //创新节点
s->key = kx;
s->leftchild = ptree->Nil;
s->rightchild = ptree->Nil;
if(kx < pa->key) //当kx 小于pa->key
{
pa->leftchild = s; //s为pa的左孩子
if(kx < ptree->head->leftchild->key) //头连着左孩子连着整个树最小关键词
{
ptree->head->leftchild = s;
}
}
else
{
pa->rightchild = s;
if(kx > ptree->head->rightchild->key) //头右孩子连着最大关键词
{
ptree->head->rightchild = s;
}
}
//
rb_node *_Y = NULL; // _Y 为叔叔节点
rb_node *_X = s; //_X在循环里为孙子节点
for(;_X != ptree->head->parent && _X->parent->color == RED ;)
{
if(_X->parent == _X->parent->parent->rightchild)
{
_Y = _X->parent->parent->leftchild;
if(_Y->color == RED) //变颜色即可
{
_Y->color = BLACK;
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
_X = _X->parent->parent;
}
else
{
if(_X->parent->leftchild == _X) //双旋情况
{
_X = _X->parent;
RotateRight(ptree,_X);
}
_X->parent->color = BLACK; //没执行上面的if为单旋
_X->parent->parent->color = RED;
RotateLeft(ptree,_X->parent->parent);
}
}
else
{
_Y = _X->parent->parent->rightchild;
if(_Y->color = RED)
{
_Y->color = BLACK;
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
_X = _X->parent->parent;
}
else
{
if(_X->parent->rightchild == _X)
{
_X = _X->parent;
RotateLeft(ptree,_X);
}
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
RotateRight(ptree,_X->parent->parent);
}
}
}
ptree->head->parent->color = BLACK; //就是上面说的根就算变红了最后循环出来涂黑就好
}
我们看一下红黑树的左旋
这个左旋和 平衡二叉树里提及的左旋是一个道理。我在AVL树博客里总结了,我这里简单提一下
节点颜色的调整都是在Insert_Item(BTree *ptree,rb_node *pa,KeyType kx)
这里左旋函数只关心节点的调整,不用关心节点颜色。
判断时候不要拿NULL 来判断,拿哨兵节点来判断
void RotateLeft(RBTree *ptree,rb_node *ptr)
{
rb_node * newroot = ptr->rightchild;
newroot->parent = ptr->parent; //1
ptr->rightchild = newroot->leftchild;
if(newroot->leftchild != ptree->Nil)
{
newroot->leftchild->parent = ptr;//2
}
newroot->leftchild = ptr;
if(ptree->head->parent == ptr)
{
ptree->head->parent = newroot;
}
else
{
if(ptr->parent->rightchild == ptr)
{
ptr->parent->rightchild = newroot;
}
else
{
ptr->parent->leftchild = newroot;
}
}
ptr->parent = newroot;
}
看下总代码
#include<iostream>
#include<stack>
#include<queue>
#include <assert.h>
using namespace std;
typedef int KeyType;
typedef enum {RED = 0, BLACK = 1} ColorType;
typedef struct rb_node
{
rb_node *leftchild;
rb_node *parent;
rb_node *rightchild;
ColorType color; //
KeyType key;
}rb_node;
typedef struct
{
rb_node *head;
rb_node *Nil;
int cursize;
}RBTree;
rb_node * Buynode(rb_node *pa = NULL,ColorType color = RED)
{
rb_node *s = (rb_node*)malloc(sizeof(rb_node));
if(NULL == s) exit(1);
memset(s,0,sizeof(rb_node));
s->parent = pa;
s->color = color;
s->leftchild = NULL;
s->rightchild = NULL;
return s;
}
void Freenode(rb_node *p)
{
free(p);
}
void Init_BTree(RBTree *ptree)
{
assert(ptree != NULL);
ptree->Nil = Buynode(NULL,BLACK);
ptree->head = Buynode(ptree->Nil,RED);
ptree->head->leftchild = ptree->Nil;
ptree->head->rightchild = ptree->Nil;
ptree->cursize = 0;
}
void RotateLeft(RBTree *ptree,rb_node *ptr)
{
rb_node * newroot = ptr->rightchild;
newroot->parent = ptr->parent; //1
ptr->rightchild = newroot->leftchild;
if(newroot->leftchild != ptree->Nil)
{
newroot->leftchild->parent = ptr;//2
}
newroot->leftchild = ptr;
if(ptree->head->parent == ptr)
{
ptree->head->parent = newroot;
}
else
{
if(ptr->parent->rightchild == ptr)
{
ptr->parent->rightchild = newroot;
}
else
{
ptr->parent->leftchild = newroot;
}
}
ptr->parent = newroot;
}
void RotateRight(RBTree *ptree,rb_node *ptr)
{
rb_node *newroot = ptr->leftchild;
ptr->leftchild = newroot->rightchild;
newroot->rightchild = ptr;
if(ptree->head->parent == ptr)
{
ptree->head->parent = newroot;
}
else
{
if(ptr->parent->leftchild == ptr)
{
ptr->parent->leftchild = newroot;
}
else
{
ptr->parent->rightchild = newroot;
}
}
}
void Insert_Item(RBTree *ptree,rb_node *pa,KeyType kx)
{
rb_node *s = Buynode(pa,RED);
s->key = kx;
s->leftchild = ptree->Nil;
s->rightchild = ptree->Nil;
if(kx < pa->key)
{
pa->leftchild = s;
if(kx < ptree->head->leftchild->key)
{
ptree->head->leftchild = s;
}
}
else
{
pa->rightchild = s;
if(kx > ptree->head->rightchild->key)
{
ptree->head->rightchild = s;
}
}
//
rb_node *_Y = NULL;
rb_node *_X = s;
for(;_X != ptree->head->parent && _X->parent->color == RED ;)
{
if(_X->parent == _X->parent->parent->rightchild)
{
_Y = _X->parent->parent->leftchild;
if(_Y->color == RED)
{
_Y->color = BLACK;
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
_X = _X->parent->parent;
}
else
{
if(_X->parent->leftchild == _X)
{
_X = _X->parent;
RotateRight(ptree,_X);
}
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
RotateLeft(ptree,_X->parent->parent);
}
}
else
{
_Y = _X->parent->parent->rightchild;
if(_Y->color = RED)
{
_Y->color = BLACK;
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
_X = _X->parent->parent;
}
else
{
if(_X->parent->rightchild == _X)
{
_X = _X->parent;
RotateLeft(ptree,_X);
}
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
RotateRight(ptree,_X->parent->parent);
}
}
}
ptree->head->parent->color = BLACK;
}
bool Insert(RBTree *ptree,KeyType kx)
{
if(ptree == NULL) return false;
if(ptree->head->parent == ptree->Nil) //此时是个空树
{
rb_node *s = Buynode(ptree->head,BLACK);
s->key = kx;
s->leftchild = ptree->Nil;
s->rightchild = ptree->Nil;
ptree->head->parent = s;
ptree->head->leftchild = s;
ptree->head->rightchild = s;
ptree->cursize = 1;
return true;
}
/
rb_node *pa = ptree->head;
rb_node *p = ptree->head->parent; // root;
while(p != ptree->Nil && p->key != kx)
{
pa = p;
p = kx < p->key ? p->leftchild:p->rightchild;
}
if(p != ptree->Nil && p->key == kx) return false;
Insert_Item(ptree,pa,kx);
ptree->cursize+=1;
return true;
}