二叉查找樹(binay scarch tree)是種帶有附加屬性的二叉樹,即對樹中的每一個結點,其左孩子都要小於其父結點,而父結點又小於或等於其右孩子。
html
二叉查找樹的定義是上章中討論的二叉樹定義的擴展。所以,下面的操做是二叉樹中已定義的那些操做的補充。二叉查找樹和平衡二叉查找樹的接口是同樣的程序列表。java
二叉查找樹的最右側結點會存放最大元素,而其最左側結點會存放最小元素.node
若是二叉查找樹不平衡,其效率可能比線性結構的還要低。git
平衡二叉樹:任何一個節點的左右子樹深度差不超過1.經過這個限定,阻止了二叉樹的左右子樹深度差較大的狀況,維持了二叉樹的穩定。算法
右旋:節點插入在最小不平衡樹的右子樹的右子樹上面。
數據結構
左旋:節點插入在最小不平衡節點的左子樹的左子樹上。
函數
右左旋:節點插入在最小不平衡樹的右子樹的左子樹上面。
學習
左右旋:節點插入在最小不平衡節點的左子樹的右子樹上面
設計
用法總結:從發生不平衡的結點起,沿剛纔回溯的路徑取直接下兩層的結點,若是這三個結點在一條直線上,則採用單旋轉進行平衡化,若是這三個結點位於一條折線上,則採用雙旋轉進行平衡化。如圖:
3d
這是一篇很好的參考資料:數據結構——平衡二叉樹
問題1:對課本removeElement方法的代碼理解有困難,主要是後面的刪除元素的圖給錯了,因而理解了半天。
問題1解決方案:其實最重要的是replacement代碼段的理解,課本給出了三種狀況的分類,「若是被刪除結點有兩個孩子,則replacement 會返回中序後繼者」這種類型的時候中序後繼者是什麼意思呢?我結合着課本給出的刪除結點的示意圖來理解。
若是刪除的節點是10,它有左右孩子,中序遍歷是先查左孩子,再是該節點,而後是右孩子,中序遍歷查找的順序是7,10,13,15 。如今10是當前所指向的結點,因此從這個步驟開始,繼續接下去的遍歷,也就是看下一個查找的元素,而後返回它,也就是返回13 。
private BinaryTreeNode<T> replacement(BinaryTreeNode<T> node) { BinaryTreeNode<T> result = null; // 若是被刪除結點沒有孩子 if ((node.left == null) && (node.right == null)) result = null; //被刪除的結點只有一個孩子,則返回孩子 else if ((node.left != null) && (node.right == null)) result = node.left; else if ((node.left == null) && (node.right != null)) result = node.right; //被刪除結點有兩個孩子,就要找的比左邊孩子小,但比該結點大的孩子。 else { BinaryTreeNode<T> current = node.right;//建立一個結點current,存放當前節點的右孩子 BinaryTreeNode<T> parent = node; while (current.left != null)//中序遍歷找到下一個結點 { parent = current; current = current.left; } current.left = node.left;//將被刪除結點的左孩子鏈到找到的這個結點的左邊 if (node.right != current)//若是這個找到的節點不是原要被刪除的結點的右孩子 { parent.left = current.right;//這時current.right爲null,parent.left從被找到的結點變爲null current.right = node.right; } result = current; } return result; }
紅黑樹中元素的插入:
1.首先插入結點。插入的結點定爲紅色( 由於將插入的節點着色爲紅色,不會違背"從樹根到樹葉的全部路徑上包含相同數目的黑色結點。",少違背一條特性,就意味着咱們須要處理的狀況越少)。
2.插入結點後的紅黑樹還是一棵二叉查找樹,可是插入後變得再也不平衡了。以後從新平衡化或者說從新着色的過程則是一種迭代的過程,因此插入節點後,咱們要作的就是將破壞紅黑樹規則的結點經過從新着色上移到別的結點。
3.接下來是分狀況討論如何變色和旋轉,使其從新平衡。
(1)其父節點爲black,這種狀況下沒有違背紅黑樹任何條件,直接插入便可(包含被插入的節點爲根節點的狀況);
(2)插入的結點的父節點是red的狀況下,又可根據叔叔結點的case劃分爲三種狀況來處理;
- case1:當叔叔結點也爲紅色時,第一,先將父節點和叔叔結點變爲black;第二,將祖父結點變爲red;最後運用遞歸繼續改變動底層的結點。
- case2:當叔叔結點是black時,若是當前結點是父節點的左孩子,則將父節點染爲black,在把祖父結點染爲red,最後以祖父節點爲支點進行右旋。
- case3:當叔叔結點是black時,而當前結點是父節點的右孩子,則以該插入的結點的父節點做爲當前節點進行左旋,變爲case2進行處理。
調整的方式:
在第三種狀況中,經過使用z的後繼節點y替換z節點,而後使用y的右孩子x來填補y的位置。在此過程須要將節點y進行移動,因爲移動以後的y節點保持原來z節點的顏色,而x節點在代替y節點以後可能會出現問題,固然只會在y節點是黑色的狀況下才會出現問題,當y節點爲紅色時,移動時紅黑樹的性質不會被破壞,y節點爲黑色時,必定會出現黑高的不相等,而且也可能會出現兩個連續的紅色節點。這時須要對其進行下一步調整。
紅黑樹的刪除
這是關於刪除的一份資料,跟着這裏面看能夠理解不少,但本身仍是有些內容理解不了,主要是刪除比插入的狀況更多並且更復雜,理解起來仍是頗有難度的。
本身編寫AVL樹時,按照對左右旋和右左旋的理解編寫的代碼是這樣的,可是參考網上的資料並和結對夥伴討論發現,你們的代碼是
這是爲何呢?
但實際上左旋中的內容實際上是右旋時進行的,而右旋時的內容纔是左旋的,我使用了參考的左、右旋代碼,因而接下去本身寫左右旋和右左旋的代碼時出現了錯誤。
其實對這幾個操做的理解仍是正確的。
問題2:
問題2解決方案:我看到這裏出錯了,還覺得是旋轉操做的書寫又發生了錯誤,但是再從新解讀了一遍本身的代碼發現徹底沒有邏輯上的錯誤,因而又花了挺久的時間,還在同窗的幫助下發現本身真的是粗心,由於本身是仿照以前的代碼寫的,因此最開始定義的是一個node,而後如今須要一個element,結果構造函數中居然沒有寫,因而發生了這種錯誤。
(statistics.sh腳本的運行結果截圖)
博客和代碼中值得學習的或問題:
這周的學習是創建在上週所學知識的基礎上的,果真基礎要打好,後面的學習纔會更有效率。不得不批評一下淘寶買來的課本了,太坑爹了,圖錯了好幾個,我一直研究,一直以爲不對,後來事實證實我是正確的,不過仍是浪費了一些時間在這個上面。雙週的課程比單週要少一些,因此這周自學Java的時間要多一些,果真知識都是靠時間換來的。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | ||
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 10/10 | |
第二週 | 326/326 | 1/2 | 18/28 | |
第三週 | 784/1110 | 1/3 | 25/53 | |
第四周 | 2529/3638 | 2/5 | 37/90 | |
第五週 | 1254/4892 | 2/7 | 20/110 | |
第六週 | 1403/6295 | 2/9 | 32/142 | |
第七週 | 1361/7656 | 1/10 | 35/177 |
計劃學習時間:30小時
實際學習時間:35小時
改進狀況:這周在概念的理解上比以往花的時間要多。