一、問題描述
實現3種樹中的兩種:紅黑樹,AVL樹,Treap樹
二、算法原理
(1)紅黑樹
紅黑樹是一種二叉查找樹,但在每個結點上增加一個存儲位表示結點的顏色,可以是red或black。紅黑樹滿足以下五個性質:
1) 每個結點或是紅色或是黑色
2) 根結點是黑色
3) 每個葉結點是黑的
4)如果一個結點是紅的,則它的兩個兒子均是黑色
5) 每個結點到其子孫結點的所有路徑上包含相同數目的黑色結點
本實驗主要實現紅黑樹的初始化,插入和刪除操作。當對紅黑樹進行插入和
刪除操作時,可能會破壞紅黑樹的五個性質。為了保證紅黑樹的性質,需要進行修改顏色和指針結構等。指針結構的修改是通過旋轉操作完成。因此這里首先描述紅黑樹的旋轉操作。
A.旋轉操作
旋轉操作主要分為左旋和右旋操作。當在某個節點x上進行左旋操作時,假設x的右孩子y不是nil[T],左旋以x到y之間的鏈為軸進行,使得y成為該子樹新的根,x成為y的左孩子,而y的左孩子則成為x的右孩子。右旋類似。
B.插入操作
紅黑樹的插入操作主要有兩個步驟。
a) 首先以二叉查找樹的方式插入一個紅色結點;
b) 然后對新的二叉樹進行修復,即進行顏色調整或旋轉操作,以此滿足紅
黑樹的五個性質。
在對紅黑樹進行插入修復操作時,循環進入條件是當前結點的父結點為紅色
即性質4破壞。在修復函數中主要考慮以下三種情況:
情況1:插入結點z的父結點為紅色,而z的叔叔結點y是紅色
此時z的父結點的父結點一定存在,而且必為黑色結點,否則插入前即不是紅黑樹。這種情況的主要思路就是修改z的父結點和叔叔結點y的顏色為黑色,z的祖父結點的顏色修改為紅色,目的就是紅色上移,然后當前結點指針指向祖父結點,循環進行修復操作
情況2:z的父結點為紅色,而z的叔叔結點y是黑色,而且z是右孩子
此時將當前節點的z的父結點設為新的當前節點,並以新當前節點為支點左旋。將情況2轉化為情況3。
情況3:z的父結點為紅色,而z的叔叔結點y是黑色,而且z是左孩子
此時將z的父節點修改為黑色,祖父節點變為紅色,並以祖父節點為支點進行右旋操作。此時一行中不再有兩個連續的紅色結點,紅黑樹所有性質調整完成,因此所有的處理到此完畢。
C.刪除操作
類似插入,紅黑樹的刪除操作主要有兩個步驟。
c) 首先以二叉查找樹的方式刪除一個指定結點;
d) 然后對新的二叉樹進行修復,即進行顏色調整或旋轉操作,以此滿足紅
黑樹的五個性質。
在對紅黑樹進行刪除修復操作時,循環進入條件是當前結點x為非根結點並
且是雙重黑結點。在修復函數中主要考慮以下四種情況:
情況1:x的兄弟結點w是紅色的
此時需把父結點修改成紅色,把兄弟結點w修改成黑色。然后,針對父結點進行左旋操作,此時紅黑樹性質5不變。將情況1轉化為其他情況。
情況2:x的兄弟w是黑色的,而且w的兩個孩子都是黑色的
此時需從當前結點x和兄弟節點w去掉一重黑色,從而x只有一重黑色而w是紅色。同時為了補償去掉的一重黑色,需在x的父結點上增加一重黑色,並把x的父結點作為新的當前節點,重新進入循環。
情況3:x的兄弟w是黑色的,w的左孩子是紅色的,右孩子是黑色的
此時需把兄弟結點w修改成紅色,兄弟w的左孩子修改成黑色,然后以兄弟結點w作為支點進行右旋操作,之后重新進入算法。將情況5轉化為情況6。
情況4:x的兄弟w是黑色的,而且w的右孩子是紅色的
此時需將兄弟結點w修改成x的父結點的顏色,然后將x的父結點修改成黑色,兄弟結點w的右孩子修改成黑色,然后以x的父結點為支點進行左旋操作。此時算法結束,紅黑樹所有性質調整完成。
D.計算根結點到葉結點所有路徑對應的黑高度
對紅黑樹進行插入或刪除結點時,為了能夠保持紅黑樹的性質會進行對應的修復操作。為了能更直觀的測試經過該修復操作后紅黑樹的性質是否正確的得到滿足,在本次實驗的結果中將依次輸出根結點到葉結點的所有路徑並輸出該路徑上所有黑色結點的個數。因此需要實現一個輸出路徑並計算對應黑高度的方法。
該方法的主要原理就是利用遞歸思想,在函數內部維護一個記錄路徑結點的數組path[]。每訪問一個結點時,首先判斷該結點是否為哨兵結點。若為哨兵,則表示該路徑已掃描結束。此時需把路徑輸出,並輸出對應黑高度。若該結點不是哨兵結點,此時需把該結點關鍵字值記錄到path[]數組中。同時如果該結點為黑色,則將表示黑高度的變量值加1.做完這些操作之后,則一次遞歸調用該結點的左右子樹。實現該操作的主要代碼如下:
E.打印樹的結構
在對紅黑樹進行插入或刪除操作之后,為了能夠更加直觀的觀察當前紅黑樹的特點,本實驗將在結果中輸出當前紅黑樹的結構。實現該操作的主要原理就是利用樹的結構特點,優先打印出右子樹,然后打印根結點值和該結點的顏色,最后打印出左子樹,在函數中通過空格來控制最后的顯示效果。主要代碼如下:
(2)AVL樹
AVL樹是一種高度平衡的二叉查找樹。它或者是一顆空樹,或者是具有下列性質的二叉樹:它的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的深度之差的絕對值不超過1。在AVL樹中的每個結點都有一個平衡因子bf,它表示這個結點的左、右子樹的高度差,即左子樹的高度減去右子樹的高度。AVL樹上所有結點的平衡因子只能是-1、0、1。
實現AVL樹的關鍵在於維持樹的平衡性。每當進行插入或刪除操作時都有可能破壞了樹的平衡性。因此首先檢查是否破壞了樹的平衡性,如果因插入結點而破壞了二叉查找樹的平衡,則找出離插入點最近的不平衡結點,然后將該不平衡結點為根的子樹進行旋轉操作。旋轉操作主要分為:LL型、RR型、LR型、RL型等。
A.旋轉操作
a) LL型
由於在A的左子樹根結點B的左子樹上插入結點,使A的平衡因子由1增至2而失去平衡。故需進行一次向右順時針旋轉操作。 即將A的左孩子B向右上旋轉代替A作為根結點,A向右下旋轉成為B的右子樹的根結點。而原來B的右子樹則變成A的左子樹。
b) RR型
由於在A的右子樹根結點B的右子樹上插入結點,使A的平衡因子由-1增至-2而失去平衡。故需進行一次向左順時針旋轉操作。
c) LR型
由於在A的左子樹根結點B的右子樹上插入結點,使A的平衡因子由1增至2而失去平衡。故需進行兩次旋轉操作,先左旋再右旋。
d) RL型
由於在A的右子樹根結點B的左子樹上插入結點,使A的平衡因子由-1增至-2而失去平衡。故需進行兩次旋轉操作,先左旋再右旋。
B.插入操作
在AVL樹上插入一個新的數據元素e的遞歸算法可描述如下:
(1)若BBST為空樹,則插入一個數據元素為e的新結點作為BBST的根結點,樹的深度增1;
(2)若e的關鍵字和BBST的根結點的關鍵字相等,則不進行;
(3)若e的關鍵字小於BBST的根結點的關鍵字,而且在BBST的左子樹中不存在和e有相同關鍵字的結點,則將e插入在BBST的左子樹上,並且當插入之后的左子樹深度增加(+1)時,分別就下列不同情況處理之:
a、BBST的根結點的平衡因子為-1(右子樹的深度大於左子樹的深度,則將根結點的平衡因子更改為0,BBST的深度不變;
b、BBST的根結點的平衡因子為0(左、右子樹的深度相等):則將根結點的平衡因子更改為1,BBST的深度增1;
c、BBST的根結點的平衡因子為1(左子樹的深度大於右子樹的深度):若BBST的左子樹根結點的平衡因子為1:則需進行單向右旋平衡處理,並且在右旋處理之后,將根結點和其右子樹根結點的平衡因子更改為0,樹的深度不變;
(4)若e的關鍵字大於BBST的根結點的關鍵字,而且在BBST的右子樹中不存在和e有相同關鍵字的結點,則將e插入在BBST的右子樹上,並且當插入之后的右子樹深度增加(+1)時,分別就不同情況處理之。
C.刪除操作
假設被刪結點x的父結點為y, 如果刪除的是y的左子樹, 則y的平衡因子bf減1, 否則y的平衡因子bf加1. 根據y的平衡因子的值分為以下三種情況:
情況一:
如果結點y的新的平衡因子bf等於0,則表示刪除前y的平衡因子等於1 或者-1, 此時高度減1, 需改變父節點和其他祖父節點的平衡因子
情況二:
如果結點y的新的平衡因子bf等於1或者-1,則表示刪除前y的平衡因子等於0, 左右子樹高度一樣, 此時高度不變, 需改變父節點和其他某些祖父節點的平衡因子.
情況三:
如果結點y新的平衡因子bf等於-2或2, 則表示刪除前y的平衡因子1等於或-1, 左右子樹高度不相同, 此時樹在結點y是不平衡的, 需要做平衡化處理
三、實驗數據
(1)輸入:
紅黑樹實驗和AVL樹實驗采用的數據均是隨機生成的20個關鍵字值。然后依次將這些關鍵字利用插入算法插入到相應樹中。在進行刪除操作時,刪除的數據是隨機選取的3個關鍵字值,然后依次刪除對應結點。
(2)輸出:
對於紅黑樹,在進行插入和刪除操作后,將輸出對應樹的結構,並標明結點的顏色(red或black),然后計算根結點到葉結點所有路徑的黑高度並依次輸出顯示。
四、源代碼
下載鏈接:http://download.csdn.net/detail/zhh1992/8359301