本週主要學習的是二叉查找樹的相關知識。二叉查找樹是一種帶有附加屬性的二叉樹,即對樹中的每一個結點。其左孩子都要小於父結點,而父結點又小於或等於右孩子。
二叉樹結點類的操做php
操做 | 說明 |
---|---|
addElement | 往樹中添加一個元素 |
removeElement | 從樹中刪除一個元素 |
removeAllOccurrences | 從樹中刪除所指定元素的任何存在 |
removeMin | 刪除樹中的最小元素 |
removeMax | 刪除樹中的最大元素 |
findMin | 返回一個指向樹中最小元素的引用 |
findMax | 返回一個指向樹中最大元素的引用 |
用鏈表實現二叉查找
樹。html
一、向鏈表中添加元素
首先判斷樹的根是否爲空,若是爲空則插入根節點中。不爲空則將添加的元素同根的左孩子進行比較。若是左孩子爲空,則將元素插入左孩子,若是元素比左孩子大,則繼續將元素同左孩子的左孩子進行比較,直至元素插入爲止。一樣,若是元素大於根,則將元素同根的右孩子進行比較,若是右孩子爲空則將元素插入右孩子,若是元素大於根的右孩子則將元素繼續同根的右孩子進行比較。直至元素插入爲止。java
二、從鏈表中刪除元素
第一種狀況:結點沒有孩子
咱們直接刪除結點便可。
第二種狀況:結點只有左孩子或者右孩子
用結點的孩子代替節點。
只有左孩子
node
只有右孩子
git
第三種狀況:結點有兩個孩子
找本身右孩子裏面的最小值(最左)而後替換本身和它,而後刪除本身
web
其餘的操做原理較爲簡單就不在贅言
11.4平衡二叉查找樹
右旋
一般是指左孩子繞着其父結點向右旋轉。
若是是由於樹根左孩子的左子樹中較長的路徑而致使的不平衡,優選能夠解決它
左旋
一般是指右孩子繞着其父結點向左旋轉。
對於有樹根右孩子的右子樹中較長路徑而致使的不平衡,左旋能夠解決它。
右左旋
對於由樹根右孩子的左子樹中較長路徑而致使的不平衡。先讓樹根右孩子的左孩子,繞着樹根的右孩子進行一次右旋,而後在讓所得的樹根右孩子繞着樹根進行一次左旋。
左右旋
對於由樹根左孩子的右子樹中較長路徑而致使的不平衡,咱們必須先讓樹根左孩子的右孩子繞着樹根的左孩子進行一次左旋,而後再讓所得的樹根左孩子繞着樹根進行一次右旋。數據結構
有序列表實現分析和二叉查找樹實現分析ide
|操做|LinkedList|BinarySearchTreeList|
|removeFirst|O(1)|O(log n)|
|remove|O(n)|O(log n)|
|remove|O(n)|O(log n)|
|first|O(1)|O(log n)|
|last|O(n)|O(log n)*|學習
|contains|O(n)|O(log n)|
|isEmpty|O(1)|O(1)|
|size|O(1)|O(1)|
|add|O(n)|O(log n)*|
11.5 實現二叉查找樹:AVL樹
AVL樹即二叉平衡查找樹,即樹的左子樹和右子樹的深度的絕對值之差不能超過1。
結點的平衡因子 = 左子樹的高度 - 右子樹的高度
插入和刪除操做都會致使AVL樹的自我調整(自我平衡),使得全部結點的平衡因子保持爲+一、-1或0。
AVL樹的右旋
若是某結點的平衡銀子爲-2,則意味着該結點的左子樹中有一條過長的路徑。因而咱們將檢查這個初始結點的左孩子的平衡因子。若是其左孩子的平衡因子是-1,則意味着較長的路徑處在這個左孩子的左子樹中,因而讓這個左孩子繞着初始結點進行一次右旋便可平衡該樹。
AVL樹的左旋
若是某結點的平衡因子是+2,則意味着該結點的右子樹中有一條過長的路徑。若是其右孩子的平衡因子是+1,則意味着其較長的路徑處在這個右孩子的右子樹中,因而讓這個右孩子繞着初始結點進行一次左旋便可平衡該樹。
AVL樹的右左旋
某結點的右子樹中有一條過長的路徑。若是其右孩子的平衡因子是-1,則意味着較長路徑處在這個右孩子的左子樹中,因而進行一次右左雙旋便可從新平衡該樹。
AVL樹的左右旋
某結點的平衡因子爲-2,則意味着該結點的左子樹中有一條過長的路徑。若是左孩子的平衡因子是+1,則意味着較長路徑處在這個左孩子的右子樹中,因而進行一次左右雙旋便可從新平衡該樹。
測試
實現二叉查找樹:紅黑樹
紅黑樹在AVL樹的基礎上有添加了兩個屬性:紅色和黑色。
紅黑樹對平衡的要求沒有AVL樹嚴格
紅黑樹紅黑顏色的要求
1.每一個節點要麼是紅色,要麼是黑色。
2.根節點必須是黑色
3.紅色節點不能連續(也便是,紅色節點的孩子和父親都不能是紅色)。
4.對於每一個節點,從該點至null(樹尾端)的任何路徑,都含有相同個數的黑色節點。
紅黑樹可以以O(log2 n)的時間複雜度進行搜索、插入、刪除操做。此外,因爲它的設計,任何不平衡都會在三次旋轉以內解決。
問題1:書上解釋蛻化樹的效率比鏈表還要低下爲何?
回答1:由於二叉搜索樹中每一個結點不只定義了其自己的元素還定義了其左孩子和右孩子的引用,而在進行查找時每每須要對其左孩子和右孩子的存在進行比較,因此效率比較低。
問題2:用Comparable接口實例化一個對象的做用。
回答2:Comparable接口是對對象進行比較的接口,使用泛型類型對對象進行實例化之後,就沒必要再去對他的方法進行重寫了能夠直接利用他實例化的對象進行compareTo比較,並且由於實例化的對象是泛型,因此利用Comparable接口進行實例化的對象能夠和任何類型的對象進行比較。接口的實例化對象能夠直接使用已經實現接口的類的方法。那麼Comparable接口實例化一個泛型隊形就可使用它對全部對象進行比較的方法。
問題:在測試二叉搜索樹時發現了這個問題
解答:後來發現是沒有寫toString方法,後來補上了。
@Override public String toString() { UnorderedListADT<BinaryTreeNode> nodes = new ArrayUnorderedList<BinaryTreeNode>(); UnorderedListADT<Integer> levelList = new ArrayUnorderedList<Integer>(); BinaryTreeNode current; String result = ""; int printDepth = this.getHeight(); int possibleNodes = (int)Math.pow(2, printDepth + 1); int countNodes = 0; nodes.addToRear(root); Integer currentLevel = 0; Integer previousLevel = -1; levelList.addToRear(currentLevel); while (countNodes < possibleNodes) { countNodes = countNodes + 1; current = nodes.removeFirst(); currentLevel = levelList.removeFirst(); if (currentLevel > previousLevel) { result = result + "\n\n"; previousLevel = currentLevel; for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++) result = result + " "; } else { for (int i = 0; i < ((Math.pow(2, (printDepth - currentLevel + 1)) - 1)) ; i++) { result = result + " "; } } if (current != null) { result = result + (current.getElement()).toString(); nodes.addToRear(current.getLeft()); levelList.addToRear(currentLevel + 1); nodes.addToRear(current.getRight()); levelList.addToRear(currentLevel + 1); } else { nodes.addToRear(null); levelList.addToRear(currentLevel + 1); nodes.addToRear(null); levelList.addToRear(currentLevel + 1); result = result + " "; } } return result; }
運行結果
80 10 85 9 16 6 44 7 85 6 85 80 16 85 9 44 6 7 80 16 9 44 6 7 80 16 9 44 7
(statistics.sh腳本的運行結果截圖)
-錯題一
-問題解答:重複將最小的元素放到最後排序的排序應該是選擇排序。
20172304郭愷郭愷同窗的博客依然是一如既往的優秀,既將教材中的內容總結的詳略得當,還能具體而全面的對本身的錯誤進行總結和提高。
20172328李馨雨李馨雨同窗的博客仍是很認真的。
上週博客互評狀況
20172304郭愷同窗本次的博客十分優秀,對教材的總結詳略得當,而又針對本身在教材中發現的問題進行了深刻的鞭辟入裏的思考與解答。整個過程看起來賞心悅目給人一種美的享受。
20172328李馨雨同窗的博客十分的完整與豐富,體現了她認真的學習態度。
本週學習了二叉搜索樹的相關知識,二叉搜索樹是二叉樹的擴展,可是新添了許多不懂的知識,並且利用了二叉樹中所學的知識,這讓我深入體會到複習的重要性,只有充分掌握已有的知識,進行吸取轉化,才能更好的利用舊知識來學習新知識。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 30/30 | 1/1 | 10/10 | |
第二週 | 766/796 | 1/2 | 40/50 | |
第三週 | 817/1613 | 1/3 | 20/70 | |
第四周 | 1370/3983 | 2/5 | 30/100 | |
第五週 | 1235/5214 | 1/6 | 10/110 | |
第六週 | 1328/6542 | 1/7 | 20/130 | |
第七週 | 1218/7860 | 1/8 | 20/150 |
1.藍墨雲班課
2.java軟件結構與數據結構
3.多動態圖詳細講解二叉搜索樹