红黑树

一、红黑树概述

  红黑树不仅是一个二叉搜索树,并且满足以下规则:

    1>每个节点不是红的就是黑的,

    2>根结点为黑色,

    3>如果节点为红色,其子节点必须为黑色,

    4>任一节点至NULL(树尾端)的任何路径,所含的黑节点的树木必须相同

二、红黑树上结点的插入

    下面分6种情况介绍红黑树的插入操作:
    1 插入点的父亲为红,父亲的兄弟节点为黑,插入点在外侧   ///把父亲染红 祖父染黑 后右旋
    2 插入点的父亲为红,父亲的兄弟节点为黑,插入点在内侧  ///先左旋后把父亲染红 祖父染黑 后右旋
    3 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧  ///把父亲及父亲的兄弟染成黑色
    4 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧  ///(父亲的祖父节点为红)
    5 插入点的父亲为红,父亲的兄弟节点为红,插入点在内侧  ///先右旋父亲改为黑祖父为红后左旋(两次旋转)
    6 插入点的父亲为黑,直接插入
    这里判断父节点是否为祖先节点的左节点和 取得伯父节点,判断伯父节点的颜色的目的是为了识别以上者6种情况

    针对双黑结点的兄弟做一次右旋转,结果使双黑结点的近侄子成为双黑结点新的兄弟;
    将新兄弟结点着为双黑结点的父结点的颜色,父结点着为黑色,再针对父做一次左旋转,

 

三、红黑树删除操作

    

一、普通二叉查找树删除一个结点:

(1)待删除结点没有子结点,即它是一个叶子结点,此时直接删除

(2)待删除结点只有一个子结点,则可以直接删除;如果待删除结点是根结点,则它的子结点变为根结点;如果待删除结点不是根结点,则用它的子结点替代它的位置。

(3)待删除结点有两个子结点,首先找出该结点的后继结点(即右子树中数值最小的那个结点),然后将两个结点进行值交换(即:只交换两个结点的数值,不改变结点的颜色)并将待删除结点删除,由于后继结点不可能有左子结点,对调后的待删除结点也不会有左子结点,因此要把它删除的操作会落入情况(1)或情况(2)中。

二、.红黑树的删除结点算法

1.待删除结点有两个外部结点,操作如下:

(1)直接把该结点调整为叶结点

(2)若该结点是红色,则可直接删除,不影响红黑树的性质,算法结束

(3)若该结点是黑色,则删除后红黑树不平衡。此时要进行“双黑”操作

记该结点为V,则删除了V后,从根结点到V的所有子孙叶结点的路径将会比树中其他的从根结点到叶结点的路径拥有更少的黑色结点, 破坏了红黑树性质4。此时,用“双黑”结点来表示从根结点到这个“双黑”结点的所有子孙叶结点的路径上都缺少一个黑色结点。  
双黑含义:该结点需要代表两个黑色结点,才能维持树的平衡

图1

如图1,要删除结点90,则删除后从根结点到结点90的所有子树结点的路径上的黑色结点比从根点到叶结点的路径上的黑结点少。因而,删除结点90后,用子结点NULL代替90结点,并置为“双黑”结点。

2.  待删除结点有一个外部结点,操作为: 
    该节点是黑色,其非空子节点为红色 ;则将其子节点提升到该结点位置,颜色变黑

3.“双黑”结点的处理

分三种情况:(1)双黑色结点的兄弟结点是黑色,且子结点有红色结点

(2)双黑结点的兄弟结点是黑色,且有两个黑色结点

                       (3)双黑结点的兄弟结点是红色结点
 
(1)双黑结点的兄弟结点是黑色,且子结点有红色结点
A种情况:双黑结点远侄子结点(双黑结点若为左孩子,则双黑结点的兄弟结点的右孩子为远侄子结点;同理,处理双黑结点为右孩子)为红色,如图2
处理方法:把兄弟结点染为双黑结点的父亲结点的颜色,把兄弟结点的右孩子染为黑色,再把父结点染为黑色;然后针对父结点进行一次左旋转,如科3。
                    
                        图2                                                                              图3
B种情况:双黑结点近侄子结点(双黑结点若为左孩子,则双黑结点的兄弟结点的左孩子为近侄子结点;同理,处理双黑结点为右孩子)为红,如图4

处理方法:针对双黑结点的兄弟做一次右旋转,结果使双黑结点的近侄子成为双黑结点新的兄弟;将新兄弟结点着为双黑结点的父结点的颜色,父结点着为黑色,再针对父做一次左旋转,如图5

 
                                图4                                                               图5

 (2)双黑结点的兄弟结点是黑色,且有两个黑色结点,如图6

 处理方法:把双黑结点的兄弟结点着为红色,双黑结点的父结点着为黑色;若父结点原来为红色,则算法结束;若父结点原来黑色,则将父结点作为双黑结点,继续调整,如图7
 
                        图6                                                                      图7
  (3)双黑结点的兄弟结点是红色结点,如图8
处理方法:单旋转为情况1或情况2,并改变双黑结点的兄弟结点的颜色及父结点的颜色(?????可能不完善),如图9
 
 
代码实现如下:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <stdlib.h>
#include <windows.h> using namespace std; typedef int Elemtype;
#define RED 0
#define BLACK 1 typedef struct Node
{
Elemtype node;
struct Node* left;
struct Node* right;
struct Node* prev;
int color;
} Node, * PNode; typedef struct RBTree
{
PNode root;
PNode data;
} RBTree, * PRBTree; int init(PRBTree tree)
{ //红黑树的初始化
if(tree == NULL) {
return ;
}
tree->data = (PNode)malloc(sizeof(Node));
tree->data->color = BLACK;
tree->root = tree->data;
return ;
}
void rotate_left(PRBTree tree, PNode x)
{
PNode y = x->right;
x->right = y->left;
if(y->left != tree->data)
{
y->left->prev = x;
}
y->prev = x->prev;
if(x == tree->root) {
tree->root = y;
}
else if(x == x->prev->left) {
x->prev->left = y;
}
else {
x->prev->right = y;
}
y->left = x;
x->prev = y;
} ///右旋
void rotate_right(PRBTree tree, PNode x)
{
PNode y = x->left;
x ->left = y->right;
if(y->right != tree->data)
{
y->right->prev = x;
}
y->prev = x->prev;
if(x == tree->root) {
tree->root = y;
}
else if(x == x->prev->left) {
x->prev->left = y;
}
else {
x->prev->right = y;
}
y->right = x;
x->prev = y;
} int insert_fixup(PRBTree tree, PNode e)
{
while(e->prev->color == RED)
{
if(e->prev->prev->left == e->prev) ///该节点的父亲节点是 左节点
{
if(e->prev->prev->right == RED)
{
e = e->prev->prev;
e->left->color = e->right->color = BLACK;
e->color = RED;
}
else
{
if(e->prev->right == e)
{
e = e->prev;
rotate_left(tree, e);
}
e->prev->color = BLACK;
e->prev->prev->color = RED;
rotate_right(tree, e->prev->prev);
}
}
else ///该节点的父亲节点是 右节点
{
if(e->prev->prev->left->color == RED)
{
e = e->prev->prev;
e->left->color = e->right ->color = BLACK;
e->color = RED;
}
else
{
if(e->prev->left == e)
{
e = e->prev;
rotate_right(tree, e);
}
e->prev->color = BLACK;
e->prev->prev->color = RED;
rotate_left(tree, e->prev->prev);
}
}
}
tree->root->color = BLACK;
return ;
} PNode insertNode(PRBTree tree, Elemtype e)
{
PNode t = NULL;
PNode p = NULL;
t = tree->root;
int flag = ;
if(tree->root == tree->data)
{
tree->root = (PNode)malloc(sizeof(Node));
tree->root->node = e;
tree->root->color = BLACK;
tree->root->prev = tree->root->left = tree->root->right = tree->data;
return tree->root;
}
while(t != tree->data)
{
p = t;
if(e < t->node)
{
flag = ;
t = t->left;
}
else
{
if(e > t->node)
{
flag = ;
t = t ->right;
}
else
{
if((flag = rand() % ) == )
{
t = t->left;
}
else
{
t = t->right;
}
}
}
}
t = (PNode)malloc(sizeof(Node));
t->node = e;
t->color = RED;
t->prev = p;
t->left = t->right = tree->data;
if(!flag)
{
p->left = t;
}
else
{
p->right = t;
}
insert_fixup(tree, t);
return t;
} ///左旋 ///找后继结点中-->右子树中数值最小的节点
PNode next(PRBTree tree, PNode t)
{
if(t == tree->data)
{
return NULL;
}
while(t->right != tree->data);
{
t = t->right;
}
return t;
} int delete_fixup(PRBTree tree, PNode c)
{
PNode b;
while(c != tree->root && c->color == BLACK)
{
if(c == c -> prev->left)
{
b = c->prev->right;
if(b->color == RED)
{
b->color = BLACK;
c->prev->color = RED;
rotate_left(tree, c->prev);
b = c->prev->right;
}
if(b->right->color == BLACK && b->left->color == BLACK)
{
b->color = RED;
c = c->prev;
}
else
{
if(b->right->color == BLACK)
{
b->color = RED;
b->left->color = BLACK;
rotate_right(tree, b);
b = c->prev->right;
}
b->color = b->prev->color;
b->prev->color = BLACK;
b->right->color = BLACK;
rotate_left(tree, c->prev);
c = tree->root;
}
}
else
{
b = c->prev->left;
if(b->color == RED)
{
b->color = BLACK;
c->prev->color = RED;
rotate_right(tree, c->prev);
b = c->prev->left;
}
if(b->right->color == BLACK && b->left->color == BLACK)
{
b->color = RED;
c = c->prev;
}
else
{
if(b->left->color == BLACK)
{
b->color = RED;
b->right->color = BLACK;
rotate_left(tree, b);
b = c->prev->left;
}
b->color = b->prev->color;
b->prev->color = BLACK;
b->left->color = BLACK;
rotate_right(tree, c->prev);
c = tree->root;
}
}
}
c->color = BLACK;
return ;
} ///删除节点
PNode destory_node(PRBTree tree, PNode t)
{
PNode c = NULL;
PNode d = NULL;
Elemtype tmp;
if(t == tree->data)
{
return NULL;
}
if(t->left != tree->data && t->right != tree->data) ///该节点有两个子节点 则找到该节点右子树中最小的值
{
d = next(tree, t);
tmp = d->node;
d->node = t->node;
t->node = tmp;
}
else
{
d = t;
}
if(d->left == tree->data)
{
c = d->right;
}
else
{
c = d->left;
}
c->prev = d->prev;
if(d->prev != tree->data)
{
if(d->prev->left == d)
{
d->prev->left = c;
}
else
{
d -> prev->right = c;
}
}
else
{
tree->root = c;
}
if(d->color == BLACK)
{
delete_fixup(tree, c);
}
return d;
} ///最小值
int minnum(PRBTree tree)
{
PNode x = tree->root;
while(x->left != tree->data)
{
x = x->left;
}
return x->node;
}
int get_root(PRBTree tree)
{
PNode x = tree->root;
return x->node;
}
///最大值
int maxnum(PRBTree tree)
{
PNode x = tree->root;
while(x->right != tree->data)
{
x = x->right;
}
return x->node;
} PNode mmap[];
void print(PRBTree tree)
{
PNode x = tree->root;
int front = ;
int rear = ;
if(tree == NULL)
{
printf("NULL\n");
return;
}
PNode tmp;
mmap[rear] = x;
int count = ;
int temp = ;
while(front <= rear)
{
tmp = mmap[front++];
count--;
if(tmp->left != tree->data)
{
mmap[++rear] = tmp->left;
temp++;
}
if(tmp->right != tree->data)
{
mmap[++rear] = tmp->right;
temp++;
}
printf("%d color = -->", tmp->node);
if(tmp->color == BLACK)
{
printf("BLACK |");
}
else
{
printf("RED |");
}
if(count == )
{
count = temp;
temp = ;
printf("\n");
}
}
return ;
}
PNode get_root1(PRBTree tree)
{
return tree->root;
}
int main()
{
PNode p ;
RBTree tree ;
init(&tree);
int i;
PNode tt , ttt;
tt = insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
insertNode(&tree, );
p = get_root1(&tree);
printf("根是------>%d\n", get_root(&tree));
printf("根是------>%d\n\n", p->node);
int mmin = minnum(&tree);
int mmax = maxnum(&tree);
printf("mmin = %d\n", mmin);
printf("mmax = %d\n\n", mmax);
print(&tree);
printf("\n删除 %d 之后树的结构是:\n\n", tt->node);
ttt = destory_node(&tree, tt);
print(&tree);
return ;
}

输出结果是:

根是------>
根是------> mmin =
mmax = color = -->BLACK |
color = -->BLACK | color = -->BLACK |
color = -->BLACK | color = -->BLACK | color = -->RED | color = -->RED |
color = -->BLACK | color = -->BLACK | color = -->BLACK | color = -->BLACK |
color = -->RED | 删除 之后树的结构是: color = -->BLACK |
color = -->BLACK | color = -->BLACK |
color = -->BLACK | color = -->RED | color = -->BLACK | color = -->BLACK |
color = -->RED | color = -->BLACK | color = -->BLACK | color = -->RED |

RBTree 红黑树的更多相关文章

  1. 红黑树(二)之 C语言的实现

    概要 红黑树在日常的使用中比较常用,例如Java的TreeMap和TreeSet,C++的STL,以及Linux内核中都有用到.之前写过一篇文章专门介绍红黑树的理论知识,本文将给出红黑数的C语言的实现 ...

  2. 红黑树的C语言实现

    rbtree.h #ifndef _RED_BLACK_TREE_H_ #define _RED_BLACK_TREE_H_ #define RED 0 // 红色节点 #define BLACK 1 ...

  3. 平衡搜索树--红黑树 RBTree

    红黑树是一棵二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是Red或Black. 通过对任何一条从根到叶子节点简单路径上的颜色来约束树的高度,红黑树保证最长路径不超过最短路径的两倍, ...

  4. java——红黑树 RBTree

    对于完全随机的数据,普通的二分搜索树就很好用,只是在极端情况下会退化成链表. 对于查询较多的情况,avl树很好用. 红黑树牺牲了平衡性,但是它的统计性能更优(综合增删改查所有的操作). 红黑树java ...

  5. 红黑树(RBTREE)之上-------构造红黑树

    该怎么说呢,现在写代码的速度还是很快的,很高兴,o(^▽^)o. 光棍节到了,早上没忍住,手贱了一般,看到*D的优惠,买了个机械键盘,晚上就到了,敲着还是很舒服的,和老婆炫耀了一把哈哈. 光棍节再去* ...

  6. 红黑树(RB-tree)比AVL树的优势在哪?

    1. 如果插入一个node引起了树的不平衡,AVL和RB-Tree都是最多只需要2次旋转操作,即两者都是O(1):但是在删除node引起树的不平衡时,最坏情况下,AVL需要维护从被删node到root ...

  7. 高级搜索树-红黑树(RBTree)代码实现

    代码实现 代码参考了<数据结构(c++语言版)>--清华大学邓俊辉 "RBTree.h" #pragma once //#include"pch.h" ...

  8. 高级搜索树-红黑树(RBTree)解析

    目录 红黑树的定义 节点与树的定义 旋转操作 插入操作 情况1:p的兄弟u为黑色 情况2: p的兄弟u为红色 插入操作性能分析 代码实现 删除操作 情况1:x的接替者succ为红色 情况2:x的接替者 ...

  9. RB-tree (红黑树)相关问题

    今天被问到了红黑树的规则,简述总结一下: 1.每个节点不是红色就是黑色. 2.根节点为黑色. 3.如果节点为红,其子节点必须为黑. 4.任一节点至NULL(树尾端)的任何路径,所含之黑节点数必须相同. ...

随机推荐

  1. 会话描述协议(SDP)介绍

    1.SDP的引入 SDP最初用于Mbone(组播骨干网)上的多媒体会议.Mbone 是Internet 的一部分,它的主要特征是对IP组播技术的使用.IP组播技术比较适合实现多方会话. 基于组播的会议 ...

  2. HDU I-最少拦截系统

    http://acm.hdu.edu.cn/showproblem.php?pid=1257 Problem Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦 ...

  3. oracle默认查询当前表空间的数据 当夸空间查询时候 需要指定具体的用户空间

  4. BZOJ4753 JSOI2016最佳团体(分数规划+树形dp)

    看到比值先二分答案.于是转化成一个非常裸的树形背包.直接暴力背包的话复杂度就是O(n2),因为相当于在lca处枚举每个点对.这里使用一种更通用的dfs序优化树形背包写法.https://www.cnb ...

  5. 【题解】AHOI2009同类分布

    好开心呀~果然只有不看题解做出来的题目才会真正的有一种骄傲与满足吧ヾ(๑╹◡╹)ノ" 实际上这题只要顺藤摸瓜就可以了.首先按照数位dp的套路,有两维想必是省不掉:1.当前dp到到的位数:2. ...

  6. 在iis上部署ssl证书 https

    1.取走证书下载下来的文件.解压iis的压缩包. 2.打开internet信息服务iis管理器 3.双击打开后,选择导入,导入我们刚刚解压得到的pfx文件,这个pfx文件就是你需要部署域名的那个文件. ...

  7. git clone 出错 fatal: pack has bad object at offset 26060927: inflate returned -3

    $ git clone http://xxx.xxx.cn/liyafei/developer.gitCloning into 'developer'...remote: Counting objec ...

  8. Nginx的火速蔓延与其并发性处理优势

    Nginx是俄罗斯人编写的十分轻量级的HTTP服务器.Nginx,它的发音为“engine X”, 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP 代理服务器.Ngi ...

  9. docker公司测试环境搭建总结

    1.防火墙转发规则: [root@docker ~]# firewall-cmd --list-allpublic (active) target: default icmp-block-invers ...

  10. (转)如何用python抓取网页并提取数据

    最近一直在学这部分,今日发现一篇好文,虽然不详细,但是轮廓是出来了: 来自crifan:http://www.crifan.com/crawl_website_html_and_extract_inf ...