13-1-1:
13-1-2:
如果是紅色,不是紅/黑樹狀結構,違反性質4;
如果是黑色,不是紅/黑樹狀結構,違反性質5;
13-1-3:
是紅/黑樹狀結構;這也就說明了,後面的插入操作和刪除操作,使違反性質的節點上移至根結點策略;
13-1-4:
度:可能是2,此時兩個子結點都是黑色的;
可能是3,此時有一個紅色子結點,一個黑色的;
可能是4,此時,有兩個紅色子結點;
深度就是black-height,因為紅色的都被吸收了;
13-1-5:
假設最短的一條長度為h1,那麼它的黑高bh1最多為h1;假設最長的一條長度為h2,那麼它的黑高bh2最少為h2/2;
因為bh1等於bh2;所以h2/2<h1即h2小於2h1;
13-1-6:
最多情況下,紅黑節點交叉分布---2^(2k+1)-1;
最少情況下,都是黑節點----2^(k)-1;
13-1-7:
最大是2:1
最小是0:1
13-2-1:
見c++代碼;
13-3-1:
如果著色為黑,那麼性質5會破壞;
13-3-2:
13-3-4:
第一種情況下:z的叔節點為紅色,z的父結點為紅色,z的祖父節點必然不能是T.nil;所以此時,T.nil不會變為紅色;
第二種情況下:沒有顏色的改變;
第三種情況下:同情況1;
所以T.nil不會被置為紅色;
13-3-5:
倘若對於第n-1個結點,沒有紅色節點;那麼插入第n個結點,一開始為紅色,就不違反紅/黑樹狀結構性質,所以第n個結點必然是紅色;
如果前n-1個結點中有紅色節點,根據RB-INSERT-FIXUP,最後必然會有紅結點;
13-3-6:
首先分析一下:
產生迭代回溯的原因是case1,否則的話,只進行一次case2和case3就可以搞定;我們不讓case1這種情況產生即可:我們採用自上而下的處理方式:假設新增節點A,那麼就沿著A的路徑,只要看到有某個節點X的另個子結點都是紅色,就把X改成紅色,並把兩個子結點改成黑色,如果此時X的父結點為紅色,那麼X的兄弟節點必然為黑色,我們對X進行case2或case3操作即可。
第二種方法就是使用棧來記錄路徑,然後把棧傳到insert_fixup,操作和書本中的操作沒有太大區別;
13-4-4:
T.nil的作用就在於刪除,T.nil的父結點可以改變;
首先當x本身就是T.nil的時候,這時候,利用T.nil尋找x的兄弟節點;
第二,w沒有孩子時;
13-1:
a.對於插入操作,從根結點到插入的節點的整條路徑都得複製;
對於刪除節點x,如果刪除的就是給定節點x,那麼所有x的祖先都得複製;
如果刪除的是x的後繼y,(即用y替換x),那麼y的祖先都得複製,x的祖先都得複製;由於x是y的祖先,所以結論:y的祖先都得複製
b下面偽碼中的new copy操作是先產生一個節點,然後把值複製進去;如果要copy的節點是NULL,那麼值為0
PERSISTENT-TREE-INSERT(T,T',k) y'=NIL x=T.root T'.root=new copy of T.root x'=T'.root while(x!=NIL) y'=x' if(k<x.key) x'.right=x.right x'.left=new copy of x.left x=x.left x'=x'.left else x'.left=x.left x'.right=new copy of x.right x=x.right x'=x'.right//此時x'即為k的插入點,y'為x'的父結點 x'.key=k
c.都是O(h)
e.13-3-6:採用棧的形式,實現insert,同理實現delete
13-2:
a.對於樹的黑高,就是根結點的黑高;對於插入操作,兩次旋轉都不會影響樹的黑高;唯一能夠改變樹的黑高的就是case1的上移操作,也就是根結點顏色的變化;對於刪除操作,旋轉也不影響樹的黑高,只有case2的上移操作至樹根,才會改變黑高;所以:當只有樹根顏色發生改變時,黑高才發生改變;
對於每個被訪問的節點,其祖先節點有x個黑色的,它的黑高就等於樹的黑高減去x;
b尋找最右面的黑高為T2.bh的節點:
FIND-MAX_IF(T1,T2.bh) bh=T1.bh x=T1.root while(bh>T2.bh) bh=bh-1 x=x.right return x
c.
RB-JOIN(Ty,x,T2) x.left=Ty.root Ty.root.p=x x.right=T2.root T2.root.p=x Ty.root=x
d染成紅色;
染成紅色後,如果原來的y就是T1的根結點,即T1.bh=T2.bh,那麼,就違反了性質1,此時,只需要把根結點顏色變為黑色,黑高加1即可;否則,如果Ty原來的父結點為紅色,那麼就可能違反性質4,此時,調用Insert-fixup進行調整即可;時間複雜度為O(lgn)
f.
RB-JOIN(T1,x,T2) if(T1.bh<=T2.bh) y=FIND-MAX_IF(T1,T2.bh) RB-JOIN(y,x,T2) INSERT-FIXUP(T1,y) else....
13-3:
假設我們插入的位置是在違反性質點的左子樹插入的,
那麼對於情況一:外側插入,
原來A子樹跟B子樹屬於同一深度,C子樹比A子樹淺一層
其中x為違反平衡的點,那麼A子樹成長了一層,致使它比C子樹的深度多了2。
此時,對X做一次右旋即可:
右旋:
AVL-ROTATE-RIGHT(T,x) y=x.left x.left=y.right if(y.right!=NIL) y.right.p=x y.p=x.p if(x.p==NIL) T.root=y elseif x==x.p.left x.p.left=y else x.p.right=y y.right=x x.p=y //調整高度: x.h=max(x.left.h,x.right.h)+1 y.h=max(y.left.h,y.right.h)+1
情況二:內側插入:
對於這種情況,
原來A子樹的深度比C子樹深一層;
先對x的left做一次左旋,轉化為外側插入:
左旋:
AVL-ROTATE-LEFT(T,x) y=x.right x.right=y.left if(y.left!=NIL) y.left.p=x y.p=x.p if(x.p==NIL) T.root=y elseif x==x.p.left x.p.left=y else x.p.right=y y.left=x x.p=y //調整高度: x.h=max(x.left.h,x.right.h)+1 y.h=max(y.left.h,x.left.h)+1
所以:
BALANCE(x):
BALANCE(x) if(x.left.h>x.right.h) if(x.left.left.h>x.left.right)//case1 AVL-RIGHT-ROTATE(T,x) else//case2 AVL-LEFT-ROTATE(T,x.left)AVL-RIGHT-ROTATE(T,x) else//對稱情況 //將上述的left與right互換
c.
AVL-INSERT(x,z) if(x==NIL) T.root=z if(z.key<x.key) if(x.left==NIL) x.left=z z.p=x _INSERT_FIXUP(T,x) else AVL-INSERT(x.left,z) else if(x.right==NIL) x.right=z z.p=x _INSERT_FIXUP(T,x) else AVL-INSERT(x.right,z) _INSERT_FIXUP(T,x) while(x!=NIL) x.h=x.h+1//先調整高度 if(x.left!=NIL&&x.right!=NIL) if(|x.left.h-x.right.h|==2) BALANCE(T,x) return else//此種情況下有一個節點為空白 if(x.left!=NIL) if(x.left==2) BALANCE(T,x) returnelseif(x.right==2) BALANCE(T,x) return x=x.p
d.最多進行兩次旋轉;
13-4:
a證明:首先優先順序最小的會當做根結點,此時對應的根結點了關鍵字確定了,剩下了節點劃分為兩組:{x1...xk}的關鍵字小於root.key,剩下的大於root.key;對於每一組,必然選擇優先順序最小的作為子樹的根結點,所以,遞迴此步驟即可得到,唯一的treap
c.
TREAP-INSERT(T,x) BST-INSERT(T,x)//普通二叉插入 while(x.p!=NIL&&x.priority<x.p.priority) if(x==x.p.left) RIGHT-ROTATE(T,x.p) else LEFT-ROTATE(T,x.p)
最多進行lgn次旋轉;