红黑树
一、红黑树概述
红黑树不仅是一个二叉搜索树,并且满足以下规则:
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)双黑结点的兄弟结点是黑色,且有两个黑色结点
#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 0; } tree->data = (PNode)malloc(sizeof(Node)); tree->data->color = BLACK; tree->root = tree->data; return 0; } 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 0; } PNode insertNode(PRBTree tree, Elemtype e) { PNode t = NULL; PNode p = NULL; t = tree->root; int flag = 0; 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 = 0; t = t->left; } else { if(e > t->node) { flag = 1; t = t ->right; } else { if((flag = rand() % 2) == 0) { 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 0; } ///删除节点 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[110]; void print(PRBTree tree) { PNode x = tree->root; int front = 0; int rear = 0; if(tree == NULL) { printf("NULL "); return; } PNode tmp; mmap[rear] = x; int count = 1; int temp = 0; 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 == 0) { count = temp; temp = 0; printf(" "); } } 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, 1); insertNode(&tree, 2); insertNode(&tree, 3); insertNode(&tree, 4); insertNode(&tree, 5); insertNode(&tree, 6); insertNode(&tree, 7); insertNode(&tree, 8); insertNode(&tree, 9); insertNode(&tree, 10); insertNode(&tree, 11); insertNode(&tree, 12); p = get_root1(&tree); printf("根是------>%d ", get_root(&tree)); printf("根是------>%d ", p->node); int mmin = minnum(&tree); int mmax = maxnum(&tree); printf("mmin = %d ", mmin); printf("mmax = %d ", mmax); print(&tree); printf(" 删除 %d 之后树的结构是: ", tt->node); ttt = destory_node(&tree, tt); print(&tree); return 0; }
输出结果是:
根是------>4 根是------>4 mmin = 1 mmax = 12 4 color = -->BLACK | 2 color = -->BLACK |8 color = -->BLACK | 1 color = -->BLACK |3 color = -->BLACK |6 color = -->RED |10 color = -->RED | 5 color = -->BLACK |7 color = -->BLACK |9 color = -->BLACK |11 color = -->BLACK | 12 color = -->RED | 删除 1 之后树的结构是: 8 color = -->BLACK | 4 color = -->BLACK |10 color = -->BLACK | 2 color = -->BLACK |6 color = -->RED |9 color = -->BLACK |11 color = -->BLACK | 3 color = -->RED |5 color = -->BLACK |7 color = -->BLACK |12 color = -->RED |