1. 程式人生 > >20172303 2018-2019-1《程式設計與資料結構》第8周學習總結

20172303 2018-2019-1《程式設計與資料結構》第8周學習總結

20172303 2018-2019-1《程式設計與資料結構》第8周學習總結

教材學習內容總結

本週的內容又是一次延續上一週學習內容掌握新知識的過程,本週學習了一種特殊形式的樹——堆,學習了兩種實現堆的方法:用連結串列實現和用陣列實現,同時還學習了使用堆來實現一種特殊佇列——優先佇列以及基於堆實現的另一種排序方法:堆排序。

一、堆的概述

  • 概念:堆是一種具有兩種附加屬性的特殊二叉樹。
    • 附加屬性一:堆是一顆完全樹(複習:完全樹:底層葉子都位於樹的左邊的平衡樹稱為完全樹)
    • 附加屬性二:對於堆中的每一個結點,該結點都小於或等於(大於或等於)它的左右孩子。
  • 型別:
    • 最小堆(小頂堆)——堆中每一個結點都小於等於其左右孩子的堆
    • 最大堆(大頂堆)——堆中每一個結點都大於等於其左右孩子的堆
  • 特點:
    1. 堆的最小值/最大值儲存在根處
    2. 堆的每一顆子樹也是一個堆

二、堆的操作

(一)堆的構造(以構造大頂堆為例)

  • 第一步:將元素按照層序遍歷的順序構造一顆二叉樹
  • 第二步:從樹中的第一個非葉子結點/非終端結點(尋找方法:樹中的第[樹中元素個數/2]個元素)開始調整,判斷該結點與其孩子的大小,如果不滿足堆的附加屬性二則進行交換。如在下圖中,第一個非葉子結點為6,它和它的右孩子9與堆的附加屬性二衝突,所以將兩者進行交換。
  • 第三步:向上繼續尋找下一個非葉子結點直至根結點,重複上一步操作,如果在交換之後存在新的不平衡,那麼針對與孩子交換之後的非葉子結點,與其新的左右孩子再次進行對比和交換。如在下圖中,第二個非葉子結點為4,它比它的兩個孩子都小,所以與其中較大的9進行交換,而在交換之後,4與它新的左孩子5和右孩子6進行對比,仍然與堆的附加屬性二衝突,所以再次對46進行交換操作。

(二)新增操作(以小頂堆中的插入為例)

  • 第一步——插入
    • 對於插入堆中的元素來說,插入時只會有一個正確的插入位置,而這個插入位置有兩種可能,假設堆的層數為h,插入元素的位置要麼在第h層的下一個靠左的空位置,要麼在第h+1層的第一個位置。
  • 第二步——調整
    • 在插入之後,將插入的元素與其父結點進行對比,如果不滿足堆的附加屬性二,則將其元素與其父結點進行對比,在必要時進行交換,直至該元素與其父結點滿足附加屬性二或位於該堆的根處。

(三)刪除操作(以小頂堆中的刪除為例)

  • 堆中的刪除操作是針對堆的根結點來進行的。
  • 第一步——刪除
    • 首先將堆的根結點刪除,然後將堆中原來的最後一個元素替換到根結點處。
  • 第二步——調整
    • 從根結點處向下,將根結點與其左右孩子進行對比,如果不符合堆的附加屬性二,則繼續交換,交換之後繼續與新的左右孩子進行比較交換,直至該元素與其左右孩子滿足附加屬性二或位於該堆的葉子處。

三、堆的實現

(一)用連結串列實現堆

  • 因為我們要求在插入元素後能夠向上遍歷該樹,所以堆中結點必須存在指向其雙親的指標。除此之外,為了能夠追蹤堆中的最末一片葉子,還要設定一個lastNode來儲存最末結點。
  • addElement
    • 該操作有三個步驟:
      • 新增新的元素到末尾,在該步驟中要確定插入結點的雙親,在最壞的情況下,它可能將整個堆遍歷,這個過程的時間複雜度為O(logn)。
      • 對堆進行重新調整,在調整過程中最多要進行logn次比較,及從下至上遍歷每一層(如果堆中有n個元素,則其高度為logn),所以其時間複雜度為O(logn)。
      • lastNode指標再次指向最末的結點,該步的時間複雜度為O(1)。
    • 所以新增操作的時間複雜度為O(logn)。
    • 在這個方法中應用了兩個私有方法getNextParentAdd(用於返回插入結點現在的父結點)和heapifyAdd(從該結點開始,對剩餘堆進行重新調整直至根處)。
  • removeMin
    • 該操作有三個步驟:
      • 用堆中的最末結點替換根結點,該步的時間複雜度為O(1)。
      • 在必要的情況下,對堆進行重新排序。該步操作與新增中的第二步類似,因此其時間複雜度為O(logn)。
      • 確定新的最末結點,在最壞的情況下,我們需要遍歷整個堆才能找到最末結點,此時它的時間複雜度為O(logn)。
    • 所以刪除操作的時間複雜度為O(logn)。
    • 在這個方法中同樣應用了兩個私有方法getNewLastNode(用於返回最末結點的引用)和heapifyRemove(從根結點開始,對下面的堆進行重新調整直至葉子結點)。

#### (二)用陣列實現堆

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

  • 問題1:
  • 問題1解決方案:
  • 問題2:
  • 問題2解決方法:
  • 問題3:
  • 問題3解決方法:

程式碼除錯中的問題和解決過程

  • 問題1:
  • 問題1解決方法:
  • 問題2:
  • 問題2解決方法:

程式碼託管

上週考試錯題總結(正確為綠色,錯誤為紅色)

  • 錯題1:The Java Collections API contains _________ implementations of an indexed list.
    • A .Two
    • B .Three
    • C .Four
    • D .Five
  • 錯題1解決方法:我本來理解的是Java API中提供了幾種方法來實現列表,因此選擇兩種因為一種是ArrayList另一種是LinkedList。後來發現是自己看錯題了沒有看到“索引”兩個字,原話在書上120頁。
  • 錯題2:The elements of an unordered list are kept in whatever order the client chooses.
    • A .True
    • B .False
  • 錯題2解決方法:當時做題的時候想的是無序列表的順序確實是由使用者來決定的啊,後來想想錯誤可能出在”whatever"上了。

結對及互評

點評模板:

  • 部落格中值得學習的或問題:
    • 優點:本週的部落格大有長進!內容豐富了很多,終於做到了圖文並茂,值得誇獎!
    • 問題:圖片的排版還需加強。
  • 程式碼中值得學習的或問題:
    • 優點:提了幾周的commit提交終於有所改進,感覺這周我的搭檔有了質的飛躍。可能是一遍遍的吐槽起了作用,果然像馬原老師說的一樣,量變會引起質變!
    • 問題:本週程式碼的備註不是很多。

      點評過的同學部落格和程式碼

  • 本週結對學習情況
    • 20172322
    • 結對學習內容
      • 給我講解了課堂實驗ASL計算的方法。
      • 主要探討了歸併排序的計數方法。

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

  • 因為跳啦啦操的緣故感覺最近的課程總是要落大家一些,現在啦啦操跳完了要趕緊追上大家ヾ(◍°∇°◍)ノ゙

學習進度條

程式碼行數(新增/累積) 部落格量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 10/10 1/1 10/10
第二週 246/366 2/3 20/30
第三週 567/903 1/4 10/40
第四周 2346/3294 2/6 20/60
第五週 2346/3294 2/8 30/90
第六週 1343/4637 2/8 20/110
第七週 654/5291 1/9 25/135
第八週 654/5291 1/10 25/160
  • 計劃學習時間:20小時

  • 實際學習時間:25小時

  • 改進情況:本週的大部分時間基本都花在了對於查詢演算法和排序演算法的理解上了,感覺對時間複雜度理解和計算的應用變得更加熟練了。

參考資料