二叉搜索树的结构:算法
typedef int ElemType; typedef struct SearchBiTree { ElemType Data; struct SearchBiTree *LChild,*RChild,*Parent; }SearchBiTree,*PSearchBiTree;
二叉搜索树的性质:函数
设 x 是二叉搜索树中的一个节点。若是 y 是 x 左子树中的一个节点,那么 y.data <= x.data。spa
若是 y 是 x 右子树中的一个节点,那么 y.data >= x.data。3d
不一样的二叉搜索树能够表明同一组值的集合。code
插入代码:blog
void Tree_Insert(PSearchBiTree &T,PSearchBiTree z) { PSearchBiTree y = NULL; PSearchBiTree x = T; while(x != NULL) { y = x; if(z->Data < x->Data) x = x->LChild; else x = x->RChild; } z->Parent = y; if(y == NULL) T = z; else if(z->Data < y->Data) y->LChild = z; else y->RChild = z; }
删除操做:class
删除操做共有以下四种状况:搜索
右下角的那种状况 Min 结点是 R子树中值最小的一个结点,因此它的左孩子为空。im
删除代码:db
一、替换函数:将结点 v 替换 T 树中的结点 u。
void Transplant(PSearchBiTree &T,PSearchBiTree u,PSearchBiTree v) { if(u->Parent == NULL) T = v; else if(u == u->Parent->LChild) u->Parent->LChild = v; else u->Parent->RChild = v; if(v != NULL) v->Parent = u->Parent; }
二、结点中的最小值。
PSearchBiTree Tree_Minimum(PSearchBiTree T) { while(T->LChild != NULL) T = T->LChild; return T; }
三、删除结点 z。
void Tree_Delete(PSearchBiTree &T,PSearchBiTree z) { PSearchBiTree y = NULL; if(z->LChild == NULL) Transplant(T,z,z->RChild); else if(z->RChild == NULL) Transplant(T,z,z->LChild); else { y = Tree_Minimum(z->RChild); if(y->Parent == z) { Transplant(T,y,y->RChild); y->RChild = z->RChild; y->RChild->Parent = y; } Transplant(T,z,y); y->LChild = z->LChild; y->LChild->Parent = y;
}
}
红黑树:
算法导论中树的高度彷佛并不算树根。
红黑树是许多"平衡"搜索树中的一种,能够保证在最坏状况下基本动态集合操做的时间复杂度为O(lgn)。
红黑树是一颗二叉搜索树,它相对二叉搜索树增长了一个存储位来标识结点颜色,可使 Red 或 Black。
经过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,确保没有一条路径会比其余路径长出两倍。
咱们一般把带关键字的结点称为内部结点,不带关键字的结点而且其没有子结点或父结点的结点称为外部结点。
红黑树结构:
typedef enum {Red,Black}RB_Color; typedef struct RBTree { ElemType Data; struct RBTree *Left,*Right,*Parent; RB_Color Color; }RBTree,*PRBTree;
红黑性质:
一、每一个结点或是红色的,或是黑色的。
二、根节点是黑色的。
三、每一个叶结点是黑色的。
四、若是一个结点是红色的,则它的两个子结点都是黑色的。
五、对每个结点,从该结点到其后代叶结点的简单路径上,均包含相同数目的黑色结点。
黑高bh:从某个结点 x 出发(不含该结点)到达一个叶结点的任意一条简单路径上的黑色结点个数,记做 bh(x)。
引理:一颗有 n 个内部结点的红黑树的高度至多为 2lg(n+1)。
推论:一颗高度为 h 的红黑树,黑高bh 至少为 (h/2)向上取整,最多为 h。
至少有 2^bh - 1 个结点,最多有 4^bh - 1个结点。
旋转操做:
如图,从右到左为左旋,从左到右为右旋。
旋转代码:
void Left_Rotate(PRBTree &T,PRBTree x) { PRBTree y = x->Right; x->Right = y->Left; if(y->Left != NULL) y->Left->Parent = x; y->Parent = x->Parent; if(x->Parent == NULL) T = y; else if(x == x->Parent->Left) x->Parent->Left = y; else x->Parent->Right = y; y->Left = x; x->Parent = y; } void Right_Rotate(PRBTree &T,PRBTree y) { PRBTree x = y->Left; y->Left = x->Right; if(x->Right != NULL) x->Right->Parent = y; x->Parent = y->Parent; if(y->Parent == NULL) T = x; else if(y == y->Parent->Left) y->Parent->Left = x; else y->Parent->Right = x; x->Right = y; y->Parent = x; }
插入操做:
在进行编写代码以前,须要分析一下全部的插入状况:
1、插入结点 A 的父结点 B 为黑色,此时插入不会破坏红黑树的性质。
2、插入结点 A 的父结点 B 为红色,且 B 结点的兄弟也为红色,
这时将不知足性质 4。但能够做相应调整:
此时,将 B 结点以及 C 结点 变成黑色,将 D 结点变成红色便可。
3、插入结点 A 的父结点 B 为红色,可是 B 结点的兄弟为黑色,
这是也不知足性质 4,也能够做出相应调整:
分别对以上四图变化后,对图1、图二先变色后,分别右旋 DB,左旋 DB。
而图3、图四分别左旋 BA,右旋 BA 后,就变成了图1、图二。
相关操做以下所示:
插入代码:
void RB_Insert(PRBTree &T,PRBTree z) { PRBTree y = NULL; PRBTree x = T; while(x != NULL) { y = x; if(z->Data < x->Data) x = x->Left; else x = x->Right; } z->Parent = y; if(y == NULL) T = z; else if(z->Data < y->Data) y->Left = z; else y->Right = z; z->Left = NULL; z->Right = NULL; z->Color = Red; RB_Insert_Fixup(T,z); }
插入修正代码:
void RB_Insert_Fixup(PRBTree &T,PRBTree z) { PRBTree y = NULL; while(z->Parent->Color = Red) { if(z->Parent == z->Parent->Parent->Left) { y = z->Parent->Parent->Right; if(y->Color == Red) { z->Parent->Color = Black; y->Color = Black; z->Parent->Parent->Color = Red; z = z->Parent->Parent; } else if(z = z->Parent->Right) { z = z->Parent; Left_Rotate(T,z); } z->Parent->Color = Black; z->Parent->Parent->Color = Red; Right_Rotate(T,z->Parent->Parent); } else { y = z->Parent->Parent->Left; if(y->Color = Red) { z->Parent->Color = Black; y->Color = Black; z->Parent->Parent->Color = Red; z = z->Parent->Parent; } else if(z == z->Parent->Left) { z = z->Parent; Left_Rotate(T,z); } z->Parent->Color = Black; z->Parent->Parent->Color = Red; Left_Rotate(T,z->Parent->Parent); } } T->Color = Black; }
删除操做:
与 n 个结点的红黑树上的其余的基本操做同样,删除一个结点须要花费 O(lgn) 时间。
下面给出几种删除状况:
1、先给出简单的删除状况:被删除结点 A 为 红色,结点 A 的兄弟和孙子没有画出。
这几种状况能够直接将结点 A 为删除,红黑树性质不会被破坏。
删除结点 A 后状况以下图:
2、比较复杂的就是以下左边的这种图,由于此时会破坏红黑性质 5 或可能破坏红黑性质 4。
让咱们先来分析一下,A 的父结点和子孙结点颜色不肯定,用蓝色表示。
如若咱们删除 A 结点,则须要寻找一个结点替代结点 A 的位置并变成结点 A 的颜色。
咱们能够寻找比 A 小且相邻的结点,也就是 A 的右子树中最小的一个结点,用 Min 表示。
咱们任然不知道结点 Min 的颜色,这里先分析简单的,让它以红色表示。
由于要保持红黑性质,因此有以下两种状况:
这两种状况只须要简单的将 Min 结点替换到 A 的位置并将颜色变成 A 的颜色便可。
3、任然是上面左边两个图,当结点 Min 的颜色是黑色时,状况就比较复杂了。
由于当移走黑色的结点 Min 后,会破坏红黑性质 5,可能会破坏红黑性质 4。
一、当 Min 结点的右孩子 C 为红色时的状况以下:
这种状况比较简单,只须要将 C 结点替换到 Min 结点的位置并将颜色变成黑色便可解决问题。
Min 的兄弟结点只画了一种状况,其余状况也同样,但要保持红黑性质。
二、当 Min 结点的右孩子为黑色时的状况以下:
当 Min 结点删除后,咱们须要找到一个红结点填到 Min 的那个路径上,并将颜色变成黑色。
因此当 P 的颜色为红色时,咱们只须要左旋一下 PB,并将 P结点颜色变成黑色便可。
可是当 P 的颜色为黑色时,咱们就得在 P 的右子树中寻找一个红结点了。
所以咱们把这两种状况和成一种状况,就是把 P 的颜色看成黑色讨论。
3.一、对于前三个图,咱们能够归为一种状况:也就是第二个图的那种状况:
第二张图的特色是 Min 结点的兄弟的右孩子 C 为 红色:
咱们先将 PB 左旋,而后颜色互换,再将 C 结点的颜色变成黑色便可。
第三个图是先将 DC 右旋,而后颜色互换,就变成了第二张图的状况。
3.二、对于第五个图其实能够和第四个图同为一种状况。
咱们已经没法在 P 树的内部寻找到一个合适的红色结点来替换 Min 的位置了。
因此此时咱们得在 P 树的祖先中寻找一个红色结点来增长 P 树的树高。
咱们将 P 结点设为新的起始点,代替原来 Min 的右结点也就是空结点。
当 P 做为新的起始点后,咱们须要判断 P 结点是其父结点的左孩子仍是右孩子。
若是是左孩子则执行相同的操做,不然便将该左旋的地方右旋,该右旋的地方左旋,
属性为 left 的地方变成 right,属性为 right 的地方变成 left。
总而言之,就是左右互换就对了。最后将起始点颜色变成黑色。
删除代码:
一、红黑树替换和寻找最小值:
void RB_Transplant(PRBTree &T,PRBTree u,PRBTree v) { if(u->Parent == NULL) T = v; else if(u == u->Parent->Left) u->Parent->Left = v; else u->Parent->Right = v; v->Parent = u->Parent; } PRBTree RBTree_Minimum(PRBTree T) { while(T->Left != NULL) T = T->Left; return T; }
二、红黑树删除:
void RB_Delete(PRBTree &T,PRBTree z) { PRBTree y = z; PRBTree x = NULL; RB_Color Original_Color = y->Color; if(z->Left = NULL) { x = z->Right; RB_Transplant(T,z,z->Right); } else if(z->Right == NULL) { x = z->Left; RB_Transplant(T,z,z->Left); } else { y = RBTree_Minimum(z->Right); Original_Color = y->Color; x = y->Right; if(y->Parent == z) x->Parent = y; else { RB_Transplant(T,y,y->Right); y->Right = z->Right; y->Right->Parent = y; } RB_Transplant(T,z,y); y->Left = z->Left; y->Left->Parent = y; y->Color = z->Color; } if(Original_Color == Black) RB_Delete_Fixup(T,x); }
三、红黑树修正:
void RB_Delete_Fixup(PRBTree &T,PRBTree x) { PRBTree w = NULL; while(x != T && x->Color == Black) { if(x == x->Parent->Left) { w = x->Parent->Right; if(w->Color == Red) { w->Color = Black; x->Parent->Color = Red; Left_Rotate(T,x->Parent); w = x->Parent->Right; } if(w->Left->Color == Black && w->Right->Color == Black) { w->Color = Red; x = x->Parent; } else { if(w->Right->Color == Black) { w->Left->Color = Black; w->Color = Red; Right_Rotate(T,w); w = x->Parent->Right; } w->Color = x->Parent->Color; x->Parent->Color = Black; w->Right->Color = Black; Left_Rotate(T,x->Parent); x = T; } } else { w = x->Parent->Left; if(w->Color == Red) { w->Color = Black; x->Parent->Color = Red; Right_Rotate(T,x->Parent); w = x->Parent->Left; } if(w->Right->Color == Black && w->Left->Color == Black) { w->Color = Red; x = x->Parent; } else { if(w->Left->Color == Black) { w->Right->Color = Black; w->Color = Red; Left_Rotate(T,w); w = x->Parent->Left; } w->Color = x->Parent->Color; x->Parent->Color = Black; w->Left->Color = Black; Right_Rotate(T,x->Parent); x = T; } } } x->Color = Black; }
如有错误请多担待,谢谢!