你們好,頭回寫博客,歡迎批評,之後我會盡可能作到一個月2更,最近在從新溫故算法。 今日提供讀書筆記紅黑樹java
記錄所學,溫故知新git
TreeMap,如下是本身安裝書中實現的原理,工做中應使用TreeMapgithub
紅黑樹(Red Black Tree) 是一種自平衡二叉查找樹.
紅黑樹和AVL樹相似,都是在進行插入和刪除操做時經過特定操做保持二叉查找樹的平衡算法
紅黑樹的插入,刪除操做在最壞狀況下花費bash
log N
複製代碼
紅黑樹是具備以下着色性質的二叉查找樹:ui
使用該着色法則,保證紅黑樹的高度最多爲:url
2*log (N+1)
複製代碼
若是新插入的項的父節點是黑色,那麼插入結束,默認新插入的節點是紅色的.spa
若是父親是紅色的,就有幾種情形(每種都有對稱形式,假設父親是曾祖父的左兒子).code
以下圖:cdn
上濾須要一個棧或者保持父鏈來實現,而且過程複雜.
概念:在向下的過程當中若是看到一個節點current有兩個紅兒子,可將該節點呈紅色,兩個兒子變爲黑色。
當current節點的父親parent也是紅色時候,進行適當的選擇,以該方式向下進行插入操做屏蔽了X節點的兄弟節點也是紅色的可能. 代碼:
/**
* 自頂向下插入
*/
public void insert( AnyType item ){
nullNode.element=item;
current=parent=grand=header;
//自頂向下調整,避免插入的父節點和父節點的兄弟節點爲黑色的狀況,該狀況複雜不利於恢復平衡信心.
while(compare(item,current)!=0){
great=grand;
grand=parent;
parent=current;
current=compare(item,current)<0?current.left:current.right;
if(current.left.color==RED&¤t.right.color==RED){
handleReorientAfterInsert(item);
}
}
if(current!=nullNode){//重複元素跳過
return;
}
//找到位置
//構建新的節點
current=new RedBlackNode<AnyType>(item,nullNode,nullNode);
//維護與父節點的關係
if(compare(item,parent)<0){
parent.left=current;
}else{
parent.right=current;
}
//插入完成後,維護平衡信息
handleReorientAfterInsert(item);
nullNode.element=null;
}
/**
* 插入後維護平衡信息
* @param item
*/
private void handleReorientAfterInsert(AnyType item) {
//初步調整的變換顏色 本身變爲紅色,兩個兒子變爲紅色
current.color=RED;
current.left.color=BLACK;
current.right.color=BLACK;
if(parent.color==RED){
//調整後破壞了紅黑樹性質,須要旋轉
//分兩種類型 一字形和之字形,之字形比一字形調整了多一步
grand.color = RED;
if((compare(item,grand)<0)!=(compare(item,parent)<0)){//之字形
parent=rotate(item,grand);
//調整parent和他的兒子,並將調整後的節點W設置成parent
}
//調整完成,從新設置當前節點
current=rotate(item,great);
//並將當前節點設置爲黑色
current.color=BLACK;
}
//保證根節點是黑色
header.right.color=BLACK;
}
複製代碼
紅色樹葉刪除簡單,若是要刪除的是黑色分爲以下幾種情:
X與兄弟T的兒子都是黑色
X的兒子是黑色,兄弟T有一個左兒子是紅色
X的兒子是黑色,兄弟T有一個右兒子是紅色
X的兒子是黑色,兄弟T兒子都是紅色
以上每種情形都有與只對應的對稱類型。若是X節點是紅色,咱們生產新的X,P,T向下探索 相關代碼:
/**
* 刪除一個節點,
* 依據能夠刪除一個葉子,
* 自頂向下刪除,
* 1若是要刪除項有右兒子,先刪除右兒子最小項,以後使用原右兒子的最小項內容替換要刪除項的內容.
* 2.若是隻有左兒子,先刪除左兒子最大,以後使用左兒子的最大項替換要刪除項的內容.
* 3.若是沒有兒子
* 若父節點爲header,將樹變爲空樹
* 不然若是當前節點爲黑色,進行調整,保證刪除項爲紅色,以後將要刪除項的父節點的引用設置爲nullNode.
* @param x
*/
public AnyType remove( AnyType x ){
//須要本身嘗試書寫
//先查找是否存在,存在後刪除
RedBlackNode<AnyType>p=find(x);
RedBlackNode<AnyType>pParent=parent;
if (p == null){
return null;
}
AnyType item=p.element;
//自頂向下刪除
//找到後,若是存在左兒子和右兒子(或 只有右兒子),
//使用右兒子的最小,替換當前 ,以後刪除右兒子最小
//只有左兒子使用左兒子最大替換,
RedBlackNode<AnyType>replacement=findReplaceMent(p);
if(replacement!=null){
//進行替換
p.element=remove(replacement.element);
}else{
//沒有替換者,
if(pParent==header){
makeEmpty();
}else{
if(p.color==BLACK){
//將p地調整爲紅色
fixbeforedelete(p.element) ;
pParent=parent;
}
//調整爲刪除
if(pParent.left==p){
pParent.left=nullNode;
}else if(pParent.right==p){
pParent.right=nullNode;
}
}
}
current=p;
parent=pParent;
return item;
}
/**
* 刪除前調整數的平衡信息,保證要刪除的項是紅色
* @param item
*/
private void fixbeforedelete(AnyType item) {
grand=header;
RedBlackNode<AnyType>p=header.right;
RedBlackNode<AnyType>x=nullNode;
RedBlackNode<AnyType>t=nullNode;
RedBlackNode<AnyType>i=find(item);
//先把p塗成紅色,最後恢復
p.color=RED;
x=item.compareTo(p.element)<=0?p.left:p.right;
t=item.compareTo(p.element)<=0?p.right:p.left;
//保證要刪除的項是紅色
while(i.color!=RED){
if(x.color==RED||
(x.color==BLACK&&(x.left.color==RED&&x.right.color==RED)||
t.color==BLACK&&(x.left.color==RED||x.right.color==RED))
){
//x爲紅色或x兒子爲紅色,x爲黑色&&t爲黑色,x有一個兒子爲紅色,向下探索
grand=p;
p=x;
x=item.compareTo(p.element)<0?p.left:p.right;
t=item.compareTo(p.element)<0?p.right:p.left;
}else if(x.color==BLACK&&t.color==BLACK
&&x.right.color==BLACK&&x.left.color==BLACK){
//3中狀況須要,調整的狀況
if(t.left.color==BLACK&&t.right.color==BLACK){
//t的兩個兒子,直接變換p和t,x的顏色,從新再該位置下探
p.color=BLACK;
t.color=RED;
x.color=RED;
}else if(t.left.color==RED&&t.right.color==RED){
//t有兩個紅色的兒子,調整後下探
if(p.right==t){
RedBlackNode<AnyType>red=t.left;
p.right=red.left;
t.left=red.right;
red.right=t;
red.left=p;
//更新祖父節點
if(grand.left==p){
grand.left=red;
}else{
grand.right=red;
}
grand=red;
p.color=BLACK;
x.color=RED;
t=p.right;
}else{
RedBlackNode<AnyType>red=t.right;
p.left=red.right;
t.right=red.left;
red.right=p;
red.left=t;
if(grand.left==p){
grand.left=red;
}else{
grand.right=red;
}
grand=red;
p.color=BLACK;
x.color=RED;
t=p.left;
}
}else if(p.right==t&&t.left.color==RED){
//右左,之字調整後繼續下探
RedBlackNode<AnyType>red=t.left;
p.right=red.left;
t.left=red.right;
red.right=t;
red.left=p;
if(grand.left==p){
grand.left=red;
}else{
grand.right=red;
}
grand=red;
p.color=BLACK;
x.color=RED;
t=p.right;
}else if(p.left==t&&(t.right.color==RED)){
//左右,之字調整後繼續下探
RedBlackNode<AnyType>red=t.right;
p.left=red.right;
t.right=red.left;
red.right=p;
red.left=t;
if(grand.left==p){
grand.left=red;
}else{
grand.right=red;
}
grand=red;
p.color=BLACK;
x.color=RED;
t=p.left;
}else if(p.right==t&&t.right.color==RED){
//右右 一字,交換t和p
p.right=t.left;
t.left=p;
if(grand.left==p){
grand.left=t;
}else{
grand.right=t;
}
grand=t;
t.color=RED;
p.color=BLACK;
t=p.right;
}else if(p.left==t&&t.left.color==RED){
//左左 一字 交換t和p
p.left=t.right;
t.right=p;
if(grand.left==p){
grand.left=t;
}else{
grand.right=t;
}
grand=t;
t.color=RED;
p.color=BLACK;
t=p.left;
}
}else if(x.color==BLACK&&p.color==BLACK&&t.color==RED){
//x的兄弟爲黑色,x和x的父節點都是紅色,調整t和p,保證p爲紅色後,繼續下探
if(p.left==x){
p.right=t.left;
t.left=p;
if(grand.left==p){
grand.left=t;
}else{
grand.right=t;
}
grand=t;
t.color=BLACK;
p.color=RED;
t=p.right;
}else{
p.left=t.right;
t.right=p;
if(grand.left==p){
grand.left=t;
}else{
grand.right=t;
}
grand=t;
t.color=BLACK;
p.color=RED;
t=p.left;
}
}else if(header.right==p&&x.color==BLACK
&&p.color==RED&&t.color==RED){
p.color=BLACK;
}
}
header.right.color=BLACK;
parent=p;
}
複製代碼
log N
複製代碼