20172306 2018-2019-2 《Java程序設計與數據結構》第八週學習總結

20172306 2018-2019-2 《Java程序設計與數據結構》第八週學習總結

教材學習內容總結

    • 堆是具備兩個附加屬性的一棵二叉樹
      • 它是一個徹底樹
      • 對每一結點,它小於或等於其左孩子和右孩子(這個描述的是最小堆)
      • 一個堆也能夠是最大堆,其中的結點大於或等於它的左右孩子
      • 它繼承了二叉樹的全部操做
    • addElement操做
      • 若是給定元素不是Comparable的,則該方法將拋出一個ClassCastException異常
      • addElement方法將給定的Comparable元素添加到堆中的恰當位置處,且維持該堆的徹底性屬性和有序屬性。
      • 由於一個堆就是一棵徹底樹,因此對於插入的新結點而言,只存在一個正確的位置,要麼就是葉子不在一層,那麼就取最後一層的空處;要麼就是在同一層,就在它的左面的第一個位置。在插入後,就會對它的完整性和有序性進行改變,因此就要進行從新的排序,拿該值和雙親結點進行比較,而後進行互換,而後沿着樹向上繼續找,直到到正確的位置。
      • 一般,在堆實現中,咱們會對樹中的最末一個結點,或更爲準確的是,最末一片葉子進行跟蹤記錄。
    • 例以下面的過程(咱們要插入的是0,由於插入後,不是最小堆,不符合規定,因此咱們進行重排序):

  • removeMin操做
    • 對於最小堆來講,Min就是根的位置的元素。因此咱們在這個方法上就是將根元素刪掉,而後再進行其餘操做。
    • 對於這個堆來講,完整性和平衡性是很重要的,因此爲了維持該樹的徹底性,只有一個能替換根的合法元素,且它是存儲在樹中最末一片葉子上的元素。對於最末一片葉子來講,就是在樹最後一層最右邊的葉子。
    • 對於addElement來講,咱們在添加的時候,有可能違背最小堆的特性,一樣,對於removeMin來講,也會出現這樣的問題,因此咱們要進行重排序以維持其原有的屬性。過程主要是將替換後的元素和它的孩子進行比較,而後依次向下,直到最後的一層,造成最小堆截止。
    • 例以下面的過程:

  • findMin操做
    • findMin就很好理解了,由於Min就是最根部的元素,因此就將返回爲root就能夠了。
  • 使用堆:優先級隊列
    • 優先級隊列(priority queue):就是遵循兩個排序規則的集合,首先,具備更高優先級的項目優先;其次,具備相同優先級的項目使用先進先出方法來肯定其排序。
    • 雖然最小堆根本不是一個隊列,可是它卻提供了一個高效的優先級隊列實現。
    • 咱們利用堆來實現一個優先級隊列:咱們要實現以上的兩個排序規則
      • 首先,咱們使用一個最小堆,須要將高優先級的項目在先
      • 其次,咱們要解決的是對相同優先級的進行先進先出的排序
        • 1.建立一個PriorityQueueNode對象,存儲將被放置在隊列中的元素,該元素的優先級,以及元素放進隊列的順序
        public PrioritizedObject(T element, int priority)
          {
        this.element = element;//元素
        this.priority = priority;//優先級
        arrivalOrder = nextOrder;//放入隊列的順序
        nextOrder++;
          }
        • 2.爲PriorityQueueNode類定義一個CompareTo方法,來完成優先級相同時的比較
        public int compareTo(PrioritizedObject obj)
          {
        int result;
        
        if (priority > obj.getPriority())
            result = 1;
        else if (priority < obj.getPriority())
            result = -1;
        else if (arrivalOrder > obj.getArrivalOrder())
            result = 1;
        else
            result = -1;
        
        return result;
          }
  • 鏈表實現和數組實現的addElement操做的時間複雜度同爲o(logn)
  • 鏈表實現和數組實現的removeMin操做的複雜度同爲o(logn)html

  • 用鏈表實現堆
    • 堆是二叉樹的一種擴展,因此在插入元素後仍舊可以向上遍歷該樹,因此堆中的結點必須存儲指向其雙親的指針。
    • 鏈表實現的實例數據由指向HeapNode且稱爲lastNode的單個引用組成,這樣咱們就可以跟蹤記錄該堆中的最末一片葉子
    public HeapNode lastNode;
    • addElement操做
      • 達到3個目的:在恰當位置處添加一個新的元素;對堆進行重排序以維持排序屬性;將lastNode指針從新設定爲指向新的最末結點
      • 其使用了兩個私有方法
        • getNextParentAdd:它返回一個指向某結點的引用,該結點爲插入結點的雙親
        • heapifyAdd:完成對堆的任何重排序,從那片新葉子開始向上處理至根處
      • 添加元素對於複雜度(複雜度爲:2*logn + 1 +logn,即o(logn)):
        • 第一步是肯定要插入結點的雙親,在最壞狀況下,要從堆的右下結點往上遍歷到根,而後再向下到堆的左下結點,時間複雜度爲2*logn
        • 下一步是插入新結點,時間複雜度爲常量
        • 最後一步是重排序,最多須要logn次操做
        • heapifyAdd未執行雙親與孩子的完整互換,只是把雙親元素向下平移到正確的插入點,而後把新值賦給該位置。但它提升了效率,由於減小了在堆的每一層上要執行的賦值次數。
    • removeMin 操做
      • 達到3個目的:用存儲在最末結點處的元素替換存儲在根處的元素;對堆重排序;返回初始的根元素。
      • 其使用了兩個私有方法
        • getNewLastNode:它返回一個指向某一結點的引用,該結點是新的最末結點
        • heapifyRemove:進行重排序(從根向下)
      • 刪除根元素對於複雜度(複雜度爲:2*logn + logn + 1,即o(logn))
        • 第一步是替換元素,其時間複雜度爲常量
        • 第二步是重排序(根往下到葉子),時間複雜度爲logn
        • 第三部爲肯定新的最末結點,和以前相同爲2*logn
    • findMin操做
      • 該元素在堆根處,只需返回根處便可
      • 複雜度爲o(1)
  • 用數組實現堆
    • 在二叉樹的數組實現中,樹的根位於位置0處,對於每一結點n,n的左孩子將位於數組的2n+1位置處,n的右孩子將位於數組的2(n+1)位置處java

    • addElement操做
      • 達到3個目的:在恰當位置處添加新結點;對堆進行重排序;將count遞增1(我認爲緣由是數組是有容量的,元素增多,要給它空間)
      • 其中有一個私有方法
        • heapifyAdd:進行重排序
      • 添加元素對於複雜度(複雜度爲:1+logn,即o(logn))
        • 不須要肯定新結點的雙親,由於會自動根據位置進行放,可是 其餘的步驟和鏈表相同。
        • 數組實現的效率更高些,但複雜度相同爲o(logn)
    • removeMin操做
      • 達到3個目的:用存儲在最末元素處的元素替換存儲在根處的元素;對堆進行重排序;返回初始的根元素
      • 其中有一個私有方法
        • 最末一個元素是存儲在數組的count-1位置處的(count是全部的元素值)
        • heapifyRemove:進行重排序
      • 刪除元素對於複雜度(複雜度爲:logn+1,即o(logn))
        • 不須要肯定新的最末結點
    • findMin操做
      • 該元素爲在根處,因此在數組的0位置處
      • 複雜度爲o(1)
  • 使用堆:堆排序老師上課用的PPT,我以爲上面的堆排序過程很詳細,並且易懂
    • heapSort方法的兩部分構成:添加列表的每一個元素,而後一次刪除一個元素git

    • 就堆排序來講,老師在上課的時候講的很詳細,並且由於它是有最小堆和最大堆的,根部要不是最小元素,要不是最大元素,所以,堆排序的關鍵就是經過不斷的移動,將最值放在根處,而後利用remove根處元素的方法,將元素刪除出來,再對剩餘的堆進行重排序,而後繼續刪除根部,而這個過程,每刪除的元素排列出來就是咱們所須要的升序或者降序,即堆排序完成算法

    • 堆排序咱們也能夠用數組的知識進行理解。由於咱們在數組實現堆時,已經知道了對於一個根結點,其左右孩子的肯定所在位置,因此咱們能夠利用比較和互換,進行排序,其實原理和上一條是相同的。api

    • 不管是用列表仍是數組進行堆排序,他們的複雜度相同,都是o(nlogn)

      數組

      • 對於列表進行堆排序來講:在前面的學習中,咱們知道,不管是addElement仍是removeMin它們的複雜度都是o(logn)。可是咱們要注意的是,這個複雜度是在添加或者刪除一個元素的狀況下的複雜度。而咱們進行排序的時候,是須要添加且刪除n個元素的,所以,咱們分別要進行這兩個操做n次,以知足對n個元素進行排序。因此最終複雜度爲2nlogn,即o(nlogn)數據結構

      • 對於數組進行堆排序來講:從數組中第一個非葉子的結點開始,將它與其孩子進行比較和互換(若有必要)。而後在數組中日後操做,直到根。對每一個非葉子的結點,最多要求進行兩次比較操做,因此複雜度爲o(n)。可是要使用這種方式從堆中刪除每一個元素並維持堆的屬性時,其複雜度仍爲o(nlogn)。所以,即便這種方式的效率稍好些,約等於2*n+logn,但其複雜度仍爲o(nlogn)。學習

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

  • 問題1:書中對於優先級隊列的內容其實挺簡略的,因此我上網找一下優先級隊列的內容
  • 問題1解決方案:
    隊列就是先進先出的一種形式,而優先級實際上就是根據某種標準進行排序,高級的就先排,對於相同級別的就根據先進先出的隊列的要求進行排序,優先級隊列也叫優先權隊列。
    對於優先級隊列的特色:
    1.優先級隊列是0個或多個元素的集合,每一個元素都有一個優先權或值。
    2.當給每一個元素分配一個數字來標記其優先級時,可設較小的數字具備較高的優先級,這樣更方便地在一個集合中訪問優先級最高的元素,並對其進行查找和刪除操做。
    3.對優先級隊列,執行的操做主要有:(1)查找,(2)插入,(3)刪除。
    4.在最小優先級隊列中,查找操做用來搜索優先權最小的元素,刪除操做用來刪除該元素。
    5.在最大優先級隊列中,查找操做用來搜索優先權最大的元素,刪除操做用來刪除該元素。
    注:咱們在刪除以後,要根據要求對以後的元素進行從新的排列,這個時候,咱們可能出現多種的相同優先權,因此,這個時候就應該根據隊列的要素,進行先進先出的進行排序,所以這也提醒咱們,咱們在寫代碼時,咱們要對進入隊列的順序進行記錄。
    6.插入操做均只是簡單地把一個新的元素加入到隊列中。測試

  • 問題2:我和曾程在宿舍看書的時候,看到getNextParentAdd這段代碼不理解,我倆都處於有點蒙圈的狀態。
private HeapNode<T> getNextParentAdd() {
        HeapNode<T> result = lastNode;

        while ((result != root) && (result.getParent().getLeft() != result))
            result = result.getParent();

        if (result != root)
            if (result.getParent().getRight() == null)
                result = result.getParent();
            else {
                result = (HeapNode<T>) result.getParent().getRight();
                while (result.getLeft() != null)
                    result = (HeapNode<T>) result.getLeft();
            }
        else
            while (result.getLeft() != null)
                result = (HeapNode<T>) result.getLeft();

        return result;
    }
  • 問題2解決方案:後來晚上聽馨雨和仇夏討論的時候,我倆也去聽了下,就懂得了。
    下面是一個本身畫的圖的過程:

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

  • 問題1:在進行ArrayHeap的測試時,出現這樣的狀況,它刪除以後,後面老是多出來一個數字,不知道爲何?
    this

  • 問題1解決方案:後來我問了譚鑫,譚鑫說,書中的removeMin少寫了一條語句,就是
tree[count - 1] = null;

而後我把它加上就正常了

後來他給我講緣由:

T minElement = tree[0];//最小的元素是根結點,也就是數組的0位置處
        tree[0] = tree[count-1];//這個時候,將最末葉子結點放在了根結點處,準備進行重排序
        tree[count-1] = null ;//將放在上面的那個最末葉子結點去掉,不然就會多出來
        heapifyRemove();//進行重排序

代碼託管

上週考試錯題總結

  • 這個是馬虎的,我後來看IDEA知道了compareTo返回的是boolean型

  • 選擇排序算法經過反覆地將某一特定值放在它的列表中的最終已排序位置從而完成對某一列表值的排序

  • 插入排序算法經過反覆地將某一特定值插入到該列表某個已排序的子集中來完成對列表值的排序

結對及互評

評分標準

  • 博客中值得學習的或問題:
    • 課本內容總結的很詳細
  • 代碼中值得學習的或問題:
    • 有的問題我沒遇到過,看到他的也算是種收穫

點評過的同窗博客和代碼

  • 本週結對學習狀況
    • 20172325
    • 結對學習內容
      • 一塊兒學習了十二章的內容
      • 共同窗習了堆的排序
      • 討論了堆的添加和刪除

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

第十二章老師講的比較簡略,主要講了堆排序的內容,說是頗有用的,並且我也聽懂了,哈哈哈!

學習進度條

代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 0/0 1/1 6/6
第二週 985/985 1/1 18/24
第三週 663/1648 1/1 16/40
第四周 1742 /3390 2/2 44/84
第五週 933/4323 1/1 23/107
第六週 1110/5433 2/2 44/151
第七週 1536/6969 1/1 56/207
第八週 1403/8372 2/2 60/267

參考資料

相關文章
相關標籤/搜索