1. 程式人生 > >20172310 2017-2018《程序設計與數據結構》(下)第七周學習總結

20172310 2017-2018《程序設計與數據結構》(下)第七周學習總結

列表 改進 詳細 運行 知識 null left 阻止 但我

20172310 2017-2018《程序設計與數據結構》(下)第七周學習總結

教材學習內容總結

本章學習的是二叉查找樹


11.1 概述

  • 二叉查找樹(binay scarch tree)是種帶有附加屬性的二叉樹,即對樹中的每個結點,其左孩子都要小於其父結點,而父結點又小於或等於其右孩子。
    技術分享圖片

  • 二叉查找樹的定義是上章中討論的二叉樹定義的擴展。因此,下面的操作是二叉樹中已定義的那些操作的補充。二叉查找樹和平衡二叉查找樹的接口是一樣的程序列表。

技術分享圖片


11.2 用鏈表實現二叉查找樹

  • BinaryTreeNode在二叉查找樹中也用來表示樹中的每個節點,每個BinaryTreeNode對象要維護一個指向結點所存儲元素的引用,另外還要維護指向結點的每個孩子的引用。

  • addElement 操作:addElement方法根據給定元素的值,在樹中的恰當位置添加該元素。
    添加元素位置的幾種情況
    • 如果這個元素不是Comparable,則addElement方法會拋出NoComparableElementException異常。
    • 如果樹為空,則這個新元素就將成為根結點。
    • 如果樹非空,且它小於根結點中存儲的那個元素且根的左孩子為null, 則這個新元素就將成為根的左孩子。如果這個新元素小於根結點中存儲的那個元素且根的左孩子不是null, 則會遍歷根的左孩子,並再次進行比較操作。
    • 如果這個新元素大於或等於樹根存儲的那個元素且根的右孩子為null, 則這個新元素會成為根的右孩子。如果這個新元素大於成等於樹根處存儲的那個元素且根的右孩子不是null,則會遍歷根的右孩子,並再次進行比較操作

技術分享圖片

  • 一旦定義了希望構造的樹的類型和樹的使用方式,也就能夠定義出該樹的接口和各種實現。

  • removeElement操作
    • removeElemcnt方法必須選出另一個結點來代替要被刪除的那個結點。private方法replacement返回指向一個結點的引用,該結點將代替要刪除的結點。
      選擇替換結點的三種情況如下:
    • 如果被刪除結點沒有孩子,則replacement返回null.
    • 如果被刪除結點只有一 個孩子, 則replacement返回這個孩子。
    • 如果被刪除結點有兩個孩子,則replacement 會返回中序後繼者(相等元素會放到右邊)。
      且這個後繼者不可能有左孩子節點,因為如果有左孩子節點則它的左孩子節點會成為那個後繼者,而不是它,因此後繼者要麽沒有孩子節點,要麽只有右孩子。

二叉查找樹的最右側結點會存放最大元素,而其最左側結點會存放最小元素.

  • removeMin操作
    按照二叉樹的定義,最小元素在二叉查找樹中只會存在於最左邊的位置,最左的位置分為有3種可能情形:
    • 如果樹根沒有左孩子,則樹根就是最小元素,而樹根的右孩了會變成新的根結點。
    • 如果樹的最左側結點是片葉子, 則這片葉子就是最小元素, 這時只需設置其父結點的左孩子引用為mull即可。
    • 如果樹的最左側結點是個內部結點,則需要設置其父結點的左孩 子引用指向這個將刪除結點的右孩子。
  • removeMax操作同理

11.3用有序列表實現二叉查找樹

  • 樹的主要使用之一就是為其他集合提供高效的實現。

技術分享圖片

  • BinarySearchTreeList實現的分析:BinarySearchTreeList 的實現是一種任何結點的最大深度為log2(n)(其中n為樹中存儲的元素數目)的平衡二叉查找樹。所以,add 操作和remove操作都要求重新平衡化樹。
  • 雖然樹實現中的有些操作更為有效,比如removeLast、last 和contains:但在利用樹實現時,也有一些操作會變得低效,比如removeFirst和first。
    技術分享圖片

11.4平衡二叉查找樹

  • 蛻化樹:如同鏈表一般,只有單邊的子樹。實際效率比鏈表還低。
    技術分享圖片
  • 如果二叉查找樹不平衡,其效率可能比線性結構的還要低。

  • 平衡二叉樹:任何一個節點的左右子樹深度差不超過1.通過這個限定,阻止了二叉樹的左右子樹深度差較大的情況,維持了二叉樹的穩定。

  • 平衡化技術中的一些方法:
    • 右旋:節點插入在最小不平衡樹的右子樹的右子樹上面。 
      技術分享圖片
      技術分享圖片

    • 左旋:節點插入在最小不平衡節點的左子樹的左子樹上。
      技術分享圖片
      技術分享圖片

    • 右左旋:節點插入在最小不平衡樹的右子樹的左子樹上面。
      技術分享圖片

    • 左右旋:節點插入在最小不平衡節點的左子樹的右子樹上面
      技術分享圖片

    • 用法總結:從發生不平衡的結點起,沿剛才回溯的路徑取直接下兩層的結點,如果這三個結點在一條直線上,則采用單旋轉進行平衡化,如果這三個結點位於一條折線上,則采用雙旋轉進行平衡化。如圖:
      技術分享圖片
      技術分享圖片

這是一篇很好的參考資料:數據結構——平衡二叉樹

  • 為了解決上述二叉排序樹這種左右子樹深度因為插入或刪除結點而不均勻的情況引入了兩種方式紅黑樹和AVL樹。

  • AVL樹:是一種平衡二叉樹的變體,其中最重要的一個概念是平衡因子:右子樹的高度減去做紫薯的高度稱為該結點的平衡因子。其旋轉方式同上。
  • 紅黑樹:
    1、根節點是黑色。
    2、如果一個節點是紅色的,則它的子節點必須是黑色的。
    3、從樹根到樹葉的所有路徑上包含相同數目的黑色結點。
    4、每個節點或者是黑色,或者是紅色。
    5、每個空結點為黑色。
    技術分享圖片

教材學習中的問題和解決過程

  • 問題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;
    }
  • 問題2:對課本中紅黑樹的操作完全看不懂。
  • 問題2解決方案:看完了課本對於紅黑樹操作的講解,我不得不說,這些字我都認識,可放在一起我怎麽就理解不了呢?(〃>皿<)
    對課本上給出的合法的紅黑樹的例子,我也表示懷疑,所以就去百度上找了一些資料來看看。
  • 紅黑樹中元素的插入:
    1.首先插入結點。插入的結點定為紅色( 因為將插入的節點著色為紅色,不會違背"從樹根到樹葉的所有路徑上包含相同數目的黑色結點。",少違背一條特性,就意味著我們需要處理的情況越少)。
    2.插入結點後的紅黑樹仍是一棵二叉查找樹,但是插入後變得不再平衡了。之後重新平衡化或者說重新著色的過程則是一種叠代的過程,所以插入節點後,我們要做的就是將破壞紅黑樹規則的結點通過重新著色上移到別的結點。
    3.接下來是分情況討論如何變色和旋轉,使其重新平衡。
    (1)其父節點為black,這種情況下沒有違背紅黑樹任何條件,直接插入即可(包含被插入的節點為根節點的情況);
    (2)插入的結點的父節點是red的情況下,又可根據叔叔結點的case劃分為三種情況來處理;
    - case1:當叔叔結點也為紅色時,第一,先將父節點和叔叔結點變為black;第二,將祖父結點變為red;最後運用遞歸繼續改變更底層的結點。
    技術分享圖片

                  - case2:當叔叔結點是black時,如果當前結點是父節點的左孩子,則將父節點染為black,在把祖父結點染為red,最後以祖父節點為支點進行右旋。

    技術分享圖片

                  - case3:當叔叔結點是black時,而當前結點是父節點的右孩子,則以該插入的結點的父節點作為當前節點進行左旋,變為case2進行處理。

技術分享圖片

  • 紅黑樹中元素的刪除
    我之前已經總結過,在一棵平衡二叉樹要刪除一個結點有三種情況。
    這三種情況在紅黑樹中一樣,但我們需要做的是將刪除後的二叉樹重新平衡和染色,現在,又可分為以下幾種情況:
    1)刪除的結點為葉子節點,然後判斷該節點是否為黑色的,若為true,則在刪除後會導致黑高不相等。於是需要對紅黑樹進行調整。
    2)刪除的結點有一個孩子節點,此時直接使用其孩子節點代替z節點,然後判斷刪除的節點是否為黑,若為true,則對紅黑樹進行調整。
    3)刪除的結點有左右孩子節點,這時首先找到該節點的後繼節點,有兩種情況:第一種情況是y是z的右孩子節點,第二種情況是y不是z的右孩子節點。

調整的方式:

  1. 當刪除情況為第一二種且結點為black時,我們可以將替代原結點的節點x再加一種再額外增加一種黑色。(網上的資料都是這樣解釋的,但是而額外增加的到底是怎麽回事我還沒有研究透徹,如果弄懂了後續再修改╭(╯^╰)╮)
  2. 技術分享圖片

在第三種情況中,通過使用z的後繼節點y替換z節點,然後使用y的右孩子x來填補y的位置。在此過程需要將節點y進行移動,由於移動之後的y節點保持原來z節點的顏色,而x節點在代替y節點之後可能會出現問題,當然只會在y節點是黑色的情況下才會出現問題,當y節點為紅色時,移動時紅黑樹的性質不會被破壞,y節點為黑色時,一定會出現黑高的不相等,並且也可能會出現兩個連續的紅色節點。這時需要對其進行下一步調整。

紅黑樹的刪除
這是關於刪除的一份資料,跟著這裏面看可以理解很多,但自己還是有些內容理解不了,主要是刪除比插入的情況更多而且更復雜,理解起來還是很有難度的。

代碼調試中的問題和解決過程

  • 問題1:XXXXXX
  • 問題1解決方案:XXXXXX
  • 問題2:XXXXXX
  • 問題2解決方案:XXXXXX
  • ...

代碼托管

(statistics.sh腳本的運行結果截圖)

上周考試錯題總結

  • 上周無錯題(ノ ̄▽ ̄)

結對及互評

點評:

  • 本周結對學習情況
    • 結對同學學號1
    • 結對學習內容
      • XXXX
      • XXXX
      • ...
  • 博客中值得學習的或問題:
    • xxx
    • xxx
    • ...
  • 代碼中值得學習的或問題:
    • xxx
    • xxx
    • ...

點評過的同學博客和代碼

  • 上周博客互評情況
    • 2017-2018-20172309 《程序設計與數據結構》第六周學習總結

    • 碼雲鏈接20172309的碼雲鏈接

其他(感悟、思考等,可選)

這周的學習是建立在上周所學知識的基礎上的,果然基礎要打好,後面的學習才會更有效率。不得不批評一下淘寶買來的課本了,太坑爹了,圖錯了好幾個,我一直研究,一直覺得不對,後來事實證明我是正確的,不過還是浪費了一些時間在這個上面。雙周的課程比單周要少一些,所以這周自學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
第七周
  • 計劃學習時間:30小時

  • 實際學習時間:XX小時

  • 改進情況:

參考資料

  • 《Java程序設計與數據結構教程(第二版)》
  • 數據結構——平衡二叉樹
  • 紅黑樹的刪除
  • 紅黑樹(一)之 原理和算法詳細介紹

20172310 2017-2018《程序設計與數據結構》(下)第七周學習總結