1. 程式人生 > >20172305 2018-2019-1 《Java軟體結構與資料結構》第七週學習總結

20172305 2018-2019-1 《Java軟體結構與資料結構》第七週學習總結

20172305 2018-2019-1 《Java軟體結構與資料結構》第七週學習總結

教材學習內容總結

本週內容主要為書第十一章內容:

  • 二叉查詢樹(附加屬性的二叉樹)
    • 二叉查詢樹是對樹中的每個結點,其左結點都要小於其父結點,而父結點又小於或等於其右結點。
    • 二叉查詢樹的定義是二叉樹定義的擴充套件。
  • LinkedBinarySearchTree類的相關方法:
    • addElement操作(類似有序列表的新增方法,元素必須是Comparable,不是的話會丟擲NoComparableElementException異常)

      • 如果樹為空,則新元素成為根結點
      • 如果樹非空,則新元素會與樹根,元素進行比較。
    • removeElement操作(類似列表的刪除指定元素的方法,找不到給定目標元素則丟擲ElementNotFoundException異常)

      • 在樹中找不到給定目標元素時,會丟擲ElementNotFoundException異常。
      • 在樹中找到給定目標元素時,如果被刪除結點沒有子結點,則替代元素為null;如果被刪除結點只有一個結點,則替代元素為該結點;如果被刪除結點有兩個子結點,則替代元素用中序查詢。
    • removeAllOccurrences操作(刪除指定元素的所有存在,如果找不到給定目標元素則丟擲ElementNotFoundException異常,如果找到元素不是Comparable,則丟擲ClassCastException異常)

      • 呼叫LinkedBinaryTree類的contains方法確定樹中是否含有目標元素。
      • 呼叫removeElement來實現刪除元素,並確保當樹中沒有該元素的時候丟擲異常。(然後捕獲異常不輸出任何內容)
    • removeMin操作(查詢最小元素 + 刪除目標元素)

      • 如果樹根沒有左子結點,則樹根就是最小元素,而樹根的右子結點將成為新的根結點。
      • 如果樹的最左側結點是葉結點,則葉結點就是最小元素,這是隻需定義父節點的左子結點為null。
      • 如果樹的最左側結點是一個內部節點,則需要設定其父節點的左結點引用指向這個將刪除結點的右結點。

  • 蛻化樹(類似連結串列,但比連結串列的效率低,每一個結點要附帶額外的開銷)

  • 平衡二叉查詢樹,自樹根而下的路徑最大長度必須不超過log2n,而且字樹根而下的路徑最小長度必須不小於log2n-1。
    • 右旋(左結點繞著其父結點向右旋轉):根結點的左子結點成為新的樹根,原根結點元素成為根節點的右子結點元素,原樹根的左子結點的右子結點成為原樹根的新的左子結點。
    • 左旋(右結點繞著其父結點向左旋轉):根結點的右子結點成為新的樹根,原根結點元素成為根節點的左子結點元素,原樹根的右子結點的左子結點成為原樹根的新的右子結點。
    • 右左旋(先讓樹根右結點的左子結點,繞著樹根的右結點進行一次右旋,然後再讓所得樹根右結點繞著樹根進行一次左旋)
    • 左右旋(先讓樹根左結點的右子結點,繞著樹根的左結點進行一次左旋,然後再讓所得樹根左結點繞著樹根進行一次右旋)
  • 平衡二叉查詢樹--AVL樹使用每個結點的平衡因子來保持二叉查詢樹平衡的策略。
    • 平衡因子:某結點的右子樹的高度減去左子樹的高度。
    • 平衡因子大於1或是小於-1則需要以該結點為樹根的子樹進行重新平衡。
  • 平衡二叉查詢樹--紅黑樹(非嚴格意義上的平衡二叉樹)使用與每個結點相關顏色(紅色或是黑色)來保持二叉查詢樹平衡的策略。

    • 紅黑樹滿足的性質:
    • (1.)每個結點或是紅色或是黑色
    • (2.)根結點是黑色的
    • (3.)每個葉結點(為空)都是黑色的
    • (4.)如果一個結點是紅色,則他的兩個子結點都是黑色
    • (5.)對每個結點,從該結點到子孫結點的所有路徑上包含相同數目的黑結點

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

  • 問題1:紅黑樹的新增刪除方法?
  • 問題1解決方案:
    • 新增元素的判斷條件:
    • 新增元素的父節點是新增元素的祖父節點的左結點:

      • 情況一新增結點的叔叔是紅色的,針對這種情況,我們將雙親結點和叔叔結點為黑色,然後將祖父結點染成紅色,再以祖父結點設為當前結點實現遞歸向上,直至到根結點為止。
      • 情況二新增結點的叔叔是黑色的,新增結點是右結點。這種情況需要先旋轉到第三種情況,即以新增結點的父結點為支點進行左旋達到第三種情況,再按照第三種情況進行。
      • 情況而新增結點的叔叔是黑色的,新增結點是左結點。這種情況需要將雙親結點染為黑色,祖父結點染為紅色,以祖父結點為支點進行左旋。
    • 新增結點的父結點是新增元素的祖父結點的右結點:

      • 第一種情況 是新增結點的叔叔是紅色的,這種情況和上一種大前提下的情況一致,將雙親結點和叔叔結點染為黑色,然後再將祖父結點染為紅色,將祖父結點視為新的結點實現遞迴,直至傳到根節點。
      • 第二種情況 是新增結點的叔叔是黑色的,而且新增結點是左子結點,這種情況需要先旋轉到第三種情況,即以新增結點的父結點為支點進行右旋達到第三種情況,再按照第三種情況進行。
      • 第三種情況 是新增結點的叔叔是黑色的,而且新增結點是右子結點。這種情況需要將雙親結點染為黑色,祖父結點染為紅色,以祖父結點為支點進行左旋。
    • 刪除操作(刪除操作理解淺談)

      • 第一種情況 刪除結點的兄弟是紅色的,刪除結點的兄弟是紅色的,那麼父親結點是黑色的,這種情況就需要改變兩個結點的顏色,然後以父結點為支點進行左旋,達到第二種情況或是第三種情況或是第四種情況
      • 第二種情況 刪除結點的兄弟是黑色的,而且兄弟結點的兩個結點都是黑色的
      • 第三種情況 刪除結點的兄弟是黑色的,而且兄弟結點的左子結點為紅色,右子結點為黑色,針對這種情況,我們先將兄弟結點和左子結點的顏色交換,即變色後以兄弟結點為支點進行右旋達到第四種情況
      • 第四種情況 刪除結點的兄弟結點是黑色的,而且兄弟結點的右結點是紅色

程式碼學習中的問題和解決過程

  • 問題1:PP11.10的add操作如何實現遞迴?
  • 問題1的解決方案:遇到這道題目,第一感覺就是很迷,不知從何下手,而且說的add操作在二叉查詢樹的連結串列實現中也叫addElement操作。而且addElement的操作用到了遞迴,一個方法呼叫另一個遞迴的方法,所以我在此基礎上進行了兩個方法的結合,常使用一個遞迴的方法來實現。其實addElement操作,之所以分成兩個方法的原因是呼叫遞迴的方法進行著根結點是否為空,空的話就實現根結點等於新增元素;以及判斷元素是否是Comparable型別,而遞迴的方法是要進行新增元素到某一個結點的左側或是右側。從兩者的實現差異來看,遞迴的方法需要兩個引數實現,而呼叫遞迴的方法只需要一個引數,把引數的內容插入到樹上就行。但是如果把兩者結合把呼叫遞迴的方法也改成兩個引數的,嘗試了一下結果是出現這種排不了序的結果。只是在上一步產生的樹的整體進行一個比較,而不是針對每一個結點的元素比較。

    • 錯誤示例:
  • 問題2:在無返回值的條件下語句有return的作用?
  • 問題2的解決方案:return的使用一直在存在返回值條件下使用,但是從未在無返回值條件下使用。如果return後面不接內容的話,就會結束該方法並不會輸出任何內容的。

      • (1.)return語句:是指結束該方法,繼續執行方法後的語句。
      • (2.)break語句:是指在迴圈中直接退出迴圈語句(for,while,do-while,foreach),break之後的迴圈體裡面的語句也執行。
      • (3.)continue語句:是指在迴圈中中斷該次迴圈語句(for,while,do-while,foreach),本次迴圈體中的continue之後語句不執行,直接跳到下次迴圈。
  • 問題3:removeMax、findMax、findMin如何編寫?

    • removeMax:刪除樹中的最大元素
    • findMax:返回樹中最小元素的引用
    • findMin:返回樹中最大元素的引用
  • 問題3解決方案:書中給出了刪除最小元素的方法,根據提供的程式碼以及二叉查詢樹的了內部結構,最小元素在根結點的左側查詢,那麼最大元素則在根結點的右側查詢。具體分析一下刪除最小元素,根據二叉查詢樹的結構可以發現在查詢最小元素的時候,如果根結點的左側沒有子結點,那麼根結點即為要刪除的最小結點,根結點的右側子節點為新的根結點。如果根結點的左側有子結點,那麼遍歷左側找到最小的結點,但是直接刪除給節點是不行的,要考慮到刪除的該結點的時候有可能存在其右子結點,這是要把右子結點移到刪除結點的位置。所以,刪除最大元素,也分兩種情況,在根結點的右側沒有子結點,那麼根結點即為要刪除的最大元素,根結點的左側元素即為根結點。如果根結點的右側右子結點,那麼遍歷右側找到最大的結點,把該結點的左子結點替代到刪除的位置。而查詢的方法只需在省略刪除結點的子結點替代刪除位置的相關程式碼就行。

  • 問題4:AVL樹的左旋、右旋、左右旋、右左旋的方法實現?
  • 問題4解決方案:AVL樹的旋轉是利用各結點的平衡因子來確定是否平衡,如果不平衡根據各結點的平衡因子的大小進行計算。

    • 左旋:根結點右子結點成為新的根結點,右子結點的左子結點成為原根節點的右子結點。
    • 右旋:根結點左子結點成為新的根結點,左子結點的右子結點成為原根結點的左子結點。
    • 左右旋:以根結點的左子結點為新的根結點,進行左旋(根結點的新左子結點為原左子結點的右子結點),然後在以原根結點進行右旋。
    • 右左旋:以根結點的右子結點為新的根結點,進行右旋(根結點的新右子結點為原右子結點的左子結點),然後在以原根結點進行左旋。
  • 問題5:AVL樹的新增和刪除方法如何編寫?
  • 問題5解決方案:
    • addElement操作:在插入元素的之前,先判斷元素是否是Comaprable型別以及判斷插入的結點是否為空,如果為空的話就構造一個新的AVL樹(左右子結點均為null),然後開始個插入結點位置進行判斷。

      • 如果比目標結點小的話,進行結點的左側插入,通過以目標結點的左子結點為新的根結點進行判斷實現遞迴操作。因為我們已經確定是在左側新增元素,那麼整棵樹的左側高度必然要大於右側高度,但是我們不確定差值是多少,但是差值也只能為-2或-1或0(右側高度減左側高度)。所以根據差值進行判斷,如果相差為-2,那麼新增元素後需要進行平衡。通過判斷新加元素在左側樹的左側還是右側,如果在左側直接進行一次右旋;在右側進行一次左右旋。
      • 如果比目標結點大或是相等的話,進行結點的右側插入,通過以目標結點的右子結點為新的根結點進行判斷實現遞迴操作。在確定在右側新增之後,右側高度會比左側高度要大,但是差值也只能為2或1或0(右側高度減左側高度)。所以根據差值進行判斷,如果相差為2,那麼新增元素後需要進行平衡。通過判斷新加元素在右側樹的左側還是右側,如果在左側直接進行一次右左旋;在右側進行一次左旋。
    • removeElement操作:在刪除元素之前,先判斷結點是否為空,在不為空的前提下進行刪除操作。

      • 如果刪除元素在根結點的左側,通過以根結點的左子結點為新的根結點進行判斷實現遞迴操作。因為在刪除元素之前,整棵樹都是平衡的,所以每個結點的平衡因子都是0或1或-1,而在刪除元素之後,導致整棵樹不平衡,但是也只會出現不平衡狀態下的平衡因子存在2(右側高度減左側高度),那麼就相當於根結點的右子結點的新增一個元素,通過比較右子結點兩側高度來判斷,如果左側高於右側就進行右左旋,如果右側高於或等於左側就進行左旋。
      • 如果刪除元素在根結點的右側,通過以根結點的右子結點為新的根結點進行判斷實現遞迴操作。因為在刪除元素之前,整棵樹都是平衡的,所以每個結點的平衡因子都是0或1或-1,而在刪除元素之後,導致整棵樹不平衡,但是也只會出現不平衡狀態下的平衡因子存在-2(右側高度減左側高度),那麼就相當於根結點的左子結點的新增一個元素,通過比較左子結點兩側高度來判斷,如果左側高於右側就進行右旋,如果右側高於或等於左側就進行左右旋。
      • 如果刪除元素是根結點,那麼如果根結點的左側右側均不為空的話,如果左子樹高於右子樹那麼從左子樹中找尋最大元素;如果右子樹高於左子樹那麼從右子樹找尋最小的元素。這種方法避免旋轉,因為無論是在左子樹內找最大的還是在右子樹中找尋最小元素替代,這兩種元素的都只是葉結點,在未刪除之前已經平衡好,平衡因子只能為0,所以替代之後也為平衡樹。
      • 如果刪除元素是根結點,那麼如果根結點沒有右子結點,那麼左子結點成為新的左結點;那麼如果根結點沒有左子結點,那麼右子結點成為新的根結點。

程式碼託管

上週考試錯題總結

上週無錯題...

結對與互評

點評(王禹涵)

  • 部落格中值得學習的或問題:
    • 背景圖很好看,還是截圖內容看得不清晰,建議換個背景圖。
  • 程式碼中值得學習的或問題:
    • 程式碼圖片也是看的不清晰,下次嘗試用電腦做出的框圖來嘗試。
  • 基於評分標準,我給本部落格打分:8分。
    • 得分情況如下:
    • 正確使用Markdown語法(加1分)
    • 模板中的要素齊全(加1分)
    • 教材學習中的問題和解決過程, 三個問題加3分
    • 程式碼除錯中的問題和解決過程, 一個問題加1分
    • 感想,體會不假大空的加1分
    • 點評認真,能指出部落格和程式碼中的問題的加1分

點評(方藝雯)

  • 部落格中值得學習的或問題:
    • 圖片特別細緻,但是針對那一大串程式碼建議配一些講解,建議不要全放到程式碼註釋中。
  • 程式碼中值得學習的或問題:
    • 程式碼問題沒有看到。
  • 基於評分標準,我給本部落格打分:6分。
  • 得分情況如下:
    • 正確使用Markdown語法(加1分)
    • 教材學習中的問題和解決過程, 三個問題加3分
    • 程式碼除錯中的問題和解決過程, 無個問題加0分
    • 感想,體會不假大空的加1分
    • 點評認真,能指出部落格和程式碼中的問題的加1分

互評物件

感悟

第十一章的二叉查詢樹學起來比樹還難學,欲哭無淚。二叉查詢樹的新增和刪除與有序列表的新增刪除差不多,每新增一個就要判斷一次還要看平不平衡,不平衡的話還得給它弄平衡了,還有紅黑樹的方法,感覺都繞暈了,特別懵,遞迴和迭代,吐血(絕望)...

學習進度條

程式碼行數(新增/累積) 部落格量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 0/0 1/1 15/15
第二週 703/703 1/2 20/35
第三週 762/1465 1/3 20/55
第四周 2073/3538 1/4 40/95
第五週 981/4519 2/6 40/135
第六週 1088/5607 2/8 50/185
第七週 1203/6810 1/9 50/235

參考資料