20172301 《程式設計與資料結構》第七週學習總結
阿新 • • 發佈:2018-11-02
20172301 《程式設計與資料結構》第七週學習總結
教材學習內容總結
- 二叉查詢樹是一種含有附加屬性的二叉樹,其左孩子小於父結點,父結點小於或者等於右孩子。
用連結串列實現二叉查詢樹
- addElement操作:根據給定元素的值,在樹中的恰當位置新增該元素。
- 判斷元素是不是Comparable,不是則丟擲異常。
- 樹為空:新元素成為根結點。
- 樹非空:新元素與根元素進行比較
- 小於:如果根的左孩子為空,成為根的左孩子;左孩子不空,遍歷新增。
- 大於:如果根的右孩子為空,成為根的右孩子;右孩子不空,遍歷新增。
- removeElement操作:從二叉查詢樹中刪除給定的Comparable元素;找不到則丟擲異常。
- 選擇替換結點的三種情況:
(1)被刪除結點沒有孩子,replacement返回null;
(2)被刪除結點有一個孩子,replacement返回這個孩子 ;
(3)被刪除結點有兩個孩子,replacement返回中序後繼者;(處於根結點右子樹上)
- 選擇替換結點的三種情況:
- removeAllOccurrences操作:從二叉查詢樹中刪除指定元素的所有存在。
- 方法使用了
LinkedBinaryTree
類的contains
方法。
- 方法使用了
- removeMin操作:
- 最小元素在二叉查詢樹的可能情況:
(1)樹根沒有左孩子,樹根即為最小元素,樹根右孩子變成新的根結點;
(2)樹的最左側結點為一片葉子,該葉子即為最小元素,設定其父結點的左孩子應用為null;
(3)樹的最左側結點為內部結點,設定其父結點的左孩子引用指向最小元素的右孩子。
- 最小元素在二叉查詢樹的可能情況:
教材學習中的問題和解決過程
- 問題1:關於書P228頁的中序後繼者的理解。
- 問題1解決方案:
- 所謂的中序後繼者意思是:中序遍歷二叉樹結點的後繼結點
- 如何查詢中序後繼者?
- 若右子樹不為空,則找到右子樹最左的葉子節點;
- 若右子樹為空,且擁有右父親節點,則找到右父親節點;
- 若右子樹為空,且擁有左父親節點,則找到最近的右祖先節點;
- 若右子樹不為空,則找到右子樹最左的葉子節點;
- 而對於刪除結點有兩個孩子的情況時,不一定replacement返回中序後繼者。也可以返回中繼前驅者。 具體的需要看程式碼實現,而不需要侷限於書本。
- 如何查詢中序前驅者?
- 若左子樹不為空,則找到左子樹的最右的葉子節點;
- 若左子樹為空,且擁有左父親節點,則找到左父親節點;
- 若左子樹為空,且擁有右父親節點,則找到最近的左父祖先節點;
- 問題2:
- 問題2解決方案:XXXXXX
- ...
程式碼除錯中的問題和解決過程
- 問題1:是否需要定義新的指標類
AVLTreeNode
,換句話說,AVL樹和二叉查詢樹以及連結串列實現的二叉樹之間的關係。 - 問題1解決方案:
首先,根據書上P240所述
由於需要上溯樹,因此AVL樹通常最好實現為每個結點都包含一個指向其父結點的引用。
- 這裡的上溯樹是因為,樹因為插入結點或者刪除結點而變得不平衡,所以每次在進行這兩個操作的時候,需要更新平衡因子,從插入或者刪除的那個結點開始,檢查到根結點。所以,我們的指標類很可能除了指向左右孩子的指標,還需要一個指向父結點的。
其次,根據書上P239所述
對於樹中的每個結點,我們都會跟蹤其左、右子樹的高度。
- 由此,指標類會需要一個
int
型變數height
,來得出結點的高度。 - 在我實現了指標類
AVLTreeNode
和LinkedAVLTree
的平衡方法後,我需要實現新增和刪除方法。但是,AVL樹和二叉查詢樹唯一不同的是新增和刪除中如果不平衡要進行旋轉。 所以,AVL樹是可以繼承二叉查詢樹的。 - 這時,其實我陷入了一個思維誤區。我寫的指標類
AVLTreeNode
因此肯定也要繼承二叉樹指標類BinaryTreeNode
。但是,其實根本不用這麼麻煩呀!
直接在BinaryTreeNode
構建新的構造方法不就可以了!
public BinaryTreeNode(T obj, LinkedBinaryTree<T> left, LinkedBinaryTree<T> right,int height)`
存在的問題:
雖然準確理解了AVL樹中旋轉平衡的操作,但是並沒有整體理解程式碼與程式碼之間的關係。花費大量的時間做了無用功,同時讓自己陷入了錯誤的迴圈。
如果,我直接發現AVL樹是二叉查詢樹的子類,那我也不會構建新的指標類。
所以,解決程式碼問題,首先需要巨集觀的觀察,確定好整體的架構,這便是UML類圖的重要性。不然,儘管你細節處理的再完美,方向錯了,便是越走越遠。先設計,考慮所有的情況,再去實現。
- 問題2:連結串列旋轉方法的順序問題。
- 問題2解決方案:這裡以右旋為例。
根據書P238 給出右旋的操作
- 使樹根的左孩子元素成為新的根元素。
- 使原根元素成為這個新樹根的右孩子元素。
- 使原樹根的左孩子的右孩子,成為原樹根的新的左孩子。
- 所以我們實現右旋方法就可以使用一下操作,其中
node
是原樹根,node1
是新樹根。
node1 = node.left; node1.right = node; node.left = node1.right;
- 然後,新增上更新高度的操作。就可以返回新的根元素。
node.height = Math.max(height(node.left),height(node.right)); node1.height = Math.max(height(node1.left),height(node1.right)); return node1;
- 執行,首先給我丟擲的是
StackOverflowError
錯誤。
- 當應用程式遞迴太深而發生堆疊溢位時,丟擲該錯誤。也就是說,方法裡出現了死遞迴。這個問題,我在上週侯澤洋同學的部落格中也看見過。
...
程式碼託管
上週考試錯題總結
上週無錯題,優秀!
結對及互評
點評過的同學部落格和程式碼
其他
學習進度條
程式碼行數(新增/累積) | 部落格量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 10/10 | |
第二週 | 610/610 | 1/2 | 20/30 | |
第三週 | 593/1230 | 1/3 | 18/48 | |
第四周 | 2011/3241 | 2/5 | 30/78 | |
第五週 | 956/4197 | 1/6 | 22/100 | |
第六週 | 2294/6491 | 2/8 | 20/120 | |
第七週 | 914/7405 | 1/9 | 20/140 |