20172325 2018-2019-2 《Java程式設計》第七週學習總結
20172325 2018-2019-2 《Java程式設計》第七週學習總結
教材學習內容總結
二叉查詢樹
- 二叉查詢樹:是含附加屬性的二叉樹,即其左孩子小於父節點,而父節點又小於或等於右孩子。
- 二叉查詢樹的定義是二叉樹定義的擴充套件。
- 二叉查詢樹的各種操作:
addElement:往樹中新增一個元素
removeElement:從樹中刪除一個元素
removeAllOccurrences:從樹中刪除所指定元素的任何存在
removeMin:刪除樹中的最小元素
removeMax:刪除樹中的最大元素
findMin:返回一個指向樹中最小元素的引用
findMax:返回一個指向樹中最大元素的引用
- 在二叉查詢樹中:
若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
葉節點的左、右子樹也分別為二叉查詢樹。
沒有鍵值相等的節點。
二叉查詢樹的刪除和插入
二叉查詢樹的插入演算法:因為二叉查詢樹是一個其結點具有特定屬性的二叉樹所以它的插入演算法就只需要一個方法,我二叉查詢樹與有序列表類似,僅需一個addElement方法就可以把一個元素插入正確的位置。具體的解決方案是:
(1)首先執行查詢演算法,找出被插結點的父親結點。
(2)判斷被插結點是其父親結點的左、右兒子。將被插結點作為葉子結點插入。
(3)若二叉樹為空。則首先單獨生成根結點。二叉查詢樹的刪除演算法:刪除結點有三種情況分別是需要刪除的結點是葉結點,是僅有左子樹/右子樹的結點,是既有左子樹又有右子樹的結點。
(1)刪除的結點是葉結點,直接讓樹結點的父結點的下一個指向null即可。
(2)刪除的結點是僅有左子樹/右子樹的結點,將該節點刪除後,將該結點的左結點/右結點提到被刪除結點的位置即可。
(3)刪除的結點是既有左子樹又有右子樹的結點,這個時候需要用到中序遍歷後的前驅結點,將前驅結點提到被刪除結點的位置。
addElement操作:就是根據給定元素的值,在樹中的恰當位置新增該元素。
如果該元素不是Comparable,該方法會丟擲NoComparableElementException異常。
如果樹為空,該元素稱為新結點。
如果樹非空,則依據二叉查詢樹的性質,分別與某結點及其左右孩子比較,按照左孩子<父節點,父節點<=右孩子的規則將其新增到適當位置,或者稱為左右孩子的孩子。
向二叉樹中新增元素
removeElement操作:從二叉查詢樹中刪除一個元素時,必須推選出另一個結點(replacement方法找到這個結點)來代替要被刪除的那個結點。
在樹中找不到給定目標元素時,丟擲ElementNotFoundException異常。
選擇替換結點的三種情況
被刪除結點沒有孩子,則replacement返回null
被刪除結點只有一個孩子,replacement返回這個孩子
被刪除結點有兩個孩子,replacement返回中序後繼者(因為相等元素會放到右邊)
removeAllOccurrences操作:從二叉查詢樹中刪除指定元素的所有存在。
在樹中找不到給定目標元素時,丟擲ElementNotFoundException異常。
如果該元素不是Comparable,該方法會丟擲ClassCastException異常。
該方法會呼叫一次removeElement方法,以確保當樹中根本不存在指定元素時會丟擲異常。
如果樹中還含有目標元素,就會再次呼叫removeElement方法。
removeMin操作:據二叉查詢樹的定義,最右側存最大的結點,最左側存最小元素。
如果樹根沒有左孩子,根結點為最小,右孩子變為新的根結點。
如果左孩子是葉子結點,將父結點的引用設為null即可。
如果左孩子是內部結點,則這個左孩子的右孩子將代替自己成為它父節點的左孩子。
平衡二叉查詢樹
- 平衡二叉查詢樹,又稱 AVL樹。 它除了具備二叉查詢樹的基本特徵之外,還具有一個非常重要的特點:它 的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的深度之差的絕對值(平衡因子 ) 不超過1。 也就是說AVL樹每個節點的平衡因子只可能是-1、0和1(左子樹高度減去右子樹高度)。
- 衡量二叉搜尋樹搜尋效率的標準:平均查詢長度(ASL):每個結點比較次數和/結點數
- 平衡因子(BF):左子樹的高度減去右子樹的高度。
- 判斷一個二叉搜尋樹是否為一個平衡二叉樹:|BF|小於等於1當對一個平衡二叉樹插入一個結點後,AVL樹就變的不平衡了
- 平衡二叉樹的調整:分為四種情況
(1)多餘點在樹的不平衡子樹的根結點的右子樹的右邊:RR插入,需要RR旋轉
(2)多餘點在樹的不平衡子樹的根結點的左子樹的左邊:LL插入,需要LL旋轉
(3)多餘點在樹的不平衡子樹的根結點的右子樹的左邊:RL插入,需要RL旋轉
(4)多餘點在樹的不平衡子樹的根結點的左子樹的右邊:LR插入,需要LR旋轉
紅黑樹
紅黑樹的特性:
(1)每個節點或者是黑色,或者是紅色。
(2)根節點是黑色。
(3)每個葉子節點(Null)是黑色。 [注意:這裡葉子節點,是指為空(NULL)的葉子節點!]即每個空結點為黑色,也即預設結點為黑色
(4)如果一個節點是紅色的,則它的子節點必須是黑色的。
(5)從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。
教材學習中的問題和解決過程
- 問題1:如何使二叉查詢樹在新增資料的同時保持平衡呢?
問題1解決方案:當在二叉排序樹中插入一個節點時,首先檢查是否因插入而破壞了平衡,若 破壞,則找出其中的最小不平衡二叉樹,在保持二叉排序樹特性的情況下,調整最小不平衡子樹中節點之間的關係,以達 到新的平衡。所謂最小不平衡子樹 指離插入節點最近且以平衡因子的絕對值大於1的節點作為根的子樹。
- 問題2:紅黑樹的插入和刪除?
問題2解決方案:
紅黑樹的插入,總是把插入的新元素的顏色設為紅色,在插入過後極大可能會導致一系列操作以再次平衡紅黑樹。
紅黑樹的刪除,與插入類似,刪除一個元素後有極大可能需要一系列操作以再次平衡紅黑樹。- 問題3:二叉查詢樹、平衡二叉樹、紅黑樹之間的優劣性差異在哪?
問題3解決方案:
二叉查詢樹的操作代價分析:
- (1) 查詢代價:
任何一個數據的查詢過程都需要從根結點出發,沿某一個路徑朝葉子結點前進。因此查詢中資料比較次數與樹的形態密切相關。
當樹中每個結點左右子樹高度大致相同時,樹高為logN。則平均查詢長度與logN成正比,查詢的平均時間複雜度在O(logN)數量級上。
當先後插入的關鍵字有序時,BST退化成單支樹結構。此時樹高n。平均查詢長度為(n+1)/2,查詢的平均時間複雜度在O(N)數量級上。 - (2) 插入代價:
新結點插入到樹的葉子上,完全不需要改變樹中原有結點的組織結構。插入一個結點的代價與查詢一個不存在的資料的代價完全相同。 - (3) 刪除代價:
當刪除一個結點P,首先需要定位到這個結點P,這個過程需要一個查詢的代價。然後稍微改變一下樹的形態。如果被刪除結點的左、右子樹只有一個存在,則改變形態的代價僅為O(1)。如果被刪除結點的左、右子樹均存在,只需要將當P的左孩子的右孩子的右孩子的…的右葉子結點與P互換,在改變一些左右子樹即可。因此刪除操作的時間複雜度最大不會超過O(logN)。 - BST效率總結 :
查詢最好時間複雜度O(logN),最壞時間複雜度O(N)。
插入刪除操作演算法簡單,時間複雜度與查詢差不多。
平衡二叉查詢樹 的操作代價分析:
二叉查詢樹在最差情況下竟然和順序查詢效率相當,這是無法仍受的。事實也證明,當儲存資料足夠大的時候,樹的結構對某些關鍵字的查詢效率影響很大。當然,造成這種情況的主要原因就是BST不夠平衡(左右子樹高度差太大)。既然如此,那麼我們就需要通過一定的演算法,將不平衡樹改變成平衡樹。因此,AVL樹就誕生了。
- (1) 查詢代價:
AVL是嚴格平衡的BST(平衡因子不超過1)。那麼查詢過程與BST一樣,只是AVL不會出現最差情況的BST(單支樹)。因此查詢效率最好,最壞情況都是O(logN)數量級的。 - (2) 插入代價:
AVL必須要保證嚴格平衡(|bf|<=1),那麼每一次插入資料使得AVL中某些結點的平衡因子超過1就必須進行旋轉操作。事實上,AVL的每一次插入結點操作最多隻需要旋轉1次(單旋轉或雙旋轉)。因此,總體上插入操作的代價仍然在O(logN)級別上(插入結點需要首先查詢插入的位置)。 - (3) 刪除代價:
AVL刪除結點的演算法可以參見BST的刪除結點,但是刪除之後必須檢查從刪除結點開始到根結點路徑上的所有結點的平衡因子。因此刪除的代價稍微要大一些。每一次刪除操作最多需要O(logN)次旋轉。因此,刪除操作的時間複雜度為O(logN)+O(logN)=O(2logN) - AVL 效率總結 :
查詢的時間複雜度維持在O(logN),不會出現最差情況
AVL樹在執行每個插入操作時最多需要1次旋轉,其時間複雜度在O(logN)左右。
AVL樹在執行刪除時代價稍大,執行每個刪除操作的時間複雜度需要O(2logN)。
紅黑樹的操作代價分析:
二叉平衡樹的嚴格平衡策略以犧牲建立查詢結構(插入,刪除操作)的代價,換來了穩定的O(logN) 的查詢時間複雜度。但是這樣做是否值得呢?
能不能找一種折中策略,即不犧牲太大的建立查詢結構的代價,也能保證穩定高效的查詢效率呢? 答案就是:紅黑樹。
- (1) 查詢代價:
由於紅黑樹的性質(最長路徑長度不超過最短路徑長度的2倍),可以說明紅黑樹雖然不像AVL一樣是嚴格平衡的,但平衡效能還是要比BST要好。其查詢代價基本維持在O(logN)左右,但在最差情況下(最長路徑是最短路徑的2倍少1),比AVL要略遜色一點。 - (2) 插入代價:
RBT插入結點時,需要旋轉操作和變色操作。但由於只需要保證RBT基本平衡就可以了。因此插入結點最多隻需要2次旋轉,這一點和AVL的插入操作一樣。雖然變色操作需要O(logN),但是變色操作十分簡單,代價很小。 - (3) 刪除代價:
RBT的刪除操作代價要比AVL要好的多,刪除一個結點最多隻需要3次旋轉操作。 - RBT 效率總結 :
查詢效率最好情況下時間複雜度為O(logN),但在最壞情況下比AVL要差一些,但也遠遠好於BST。
插入和刪除操作改變樹的平衡性的概率要遠遠小於AVL(RBT不是高度平衡的)。因此需要的旋轉操作的可能性要小,而且一旦需要旋轉,插入一個結點最多隻需要旋轉2次,刪除最多隻需要旋轉3次(小於AVL的刪除操作所需要的旋轉次數)。雖然變色操作的時間複雜度在O(logN),但是實際上,這種操作由於簡單所需要的代價很小。
程式碼除錯中的問題和解決過程
- 問題1:AVL樹的左旋、右旋、左右旋、右左旋怎麼實現?
- 問題1解決方案:參考藍墨雲資源,發現部落格《AVL樹(三)之 Java的實現》,試了其中的程式碼,解決了問題,明白了什麼意思。
- 問題2:不會定義紅黑樹的節點
- 問題2解決方案:查閱了資料,詢問了結對夥伴
private static class Node<AnyType>{
Node(AnyType d){
this.data =d;
this.left =null;
this.right =null;
this.parent =null;
this.color =RBTree.BLACK;
}
Node(AnyType d, Node<AnyType> left, Node<AnyType> right,Node<AnyType> parent,boolean color){
this.data =d;
this.left =left;
this.right =right;
this.parent =parent;
this.color =color;
}
AnyType data;
Node<AnyType> left;
Node<AnyType> right;
Node<AnyType> parent;
boolean color;
}
程式碼託管
(statistics.sh指令碼的執行結果截圖)
上週考試錯題總結
無
結對及互評
- 本週結對學習情況
- 20172306
- 結對學習內容
- 第十一章教材
- 第十一章程式碼
- 紅黑樹的相關討論
學習進度條
程式碼行數(新增/累積) | 部落格量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 20/20 | |
第二週 | 941/8481 | 1/2 | 18/20 | |
第三週 | 653/9134 | 1/3 | 22/20 | |
第四周 | 1728/4385 | 2/5 | 8/28 | |
第五週 | 933/5318 | 1/6 | 18/20 | |
第六週 | 1082/5877 | 1/7 | 20/18 | |
第七週 | / | 1/8 | 18/18 |