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

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

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

教材學習內容總結

第十五章 圖

圖:

堆是具有兩個附加屬性得的一棵二叉樹:

  • 它是一棵完全樹;
  • 對每一節點,它小(大)於或等於其左孩子和右孩子。

堆的分類:按照堆中元素排列規律將堆分為兩類:

  • 最小堆(minheap),本章介紹中預設的堆的型別,對每一節點,它小於或等於其左孩子和右孩子

  • 最大堆(maxheap),與最小堆相反(對每一節點,它大於或等於其左孩子和右孩子)

優先順序佇列(priority queue):
排序規則:

  • 具有更高優先順序的項在前;
  • 具有相同優先順序的專案按照先進先出方法來確定排序。

回顧知識點:完全樹,樹最底層的葉子都在樹的左邊

堆介面的方法(最小堆)
| 操作 | 說明 |
|:---------:|:-------------------:|
|addElement | 將給定元素新增到該堆中 |
|removeMin | 刪除堆中的最小元素 |
|findMin | 返回一個指向堆中最小元素的引用 |

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

  1. 建立一個堆之後進行多次addElement()操作新增元素後,還需要進行重排序?

選擇陣列addElement()分析,較為簡短:

public void addElement(T obj) 
    {
        if (count == tree.length)
            expandCapacity();

        tree[count] = obj;
        count++;
        modCount++;

        if (count > 1)
            heapifyAdd();
    }

    private void heapifyAdd()
    {
        T temp;
        int next = count - 1;
        
        temp = tree[next];
        
        while ((next != 0) && 
            (((Comparable)temp).compareTo(tree[(next-1)/2]) < 0))
        {
            tree[next] = tree[(next-1)/2];
            next = (next-1)/2;
        }

        tree[next] = temp;
    }

檢查程式碼,發現:在插入過程中addElement()方法引用了heapifyAdd()方法,addElement()方法僅作插入,將指定元素放到最末節點,如果不進行重排序,堆就不一定會符合小項在上的規則。

重排序和插入是同時進行的,而不是我之前理解的:先插入後排序

同樣的問題,removeMin()方法刪除最小元素(最頂端),要維持堆的完全性,替換它的元素是最末的元素,此時也需要進行重排序:

private void heapifyRemove()
    {
        T temp;
        int node = 0;
        int left = 1;
        int right = 2;
        int next;
        
        if ((tree[left] == null) && (tree[right] == null))
            next = count;
        else if (tree[right] == null)
            next = left;
        else if (((Comparable)tree[left]).compareTo(tree[right]) < 0)
            next = left;
        else
            next = right;
        temp = tree[node];

        while ((next < count) && 
            (((Comparable)tree[next]).compareTo(temp) < 0))
        {
            tree[node] = tree[next];
            node = next;
            left = 2 * node + 1;
            right = 2 * (node + 1);
            if ((tree[left] == null) && (tree[right] == null))
                next = count;
            else if (tree[right] == null)
                next = left;
            else if (((Comparable)tree[left]).compareTo(tree[right]) < 0)
                next = left;
            else
                next = right;
        }
        tree[node] = temp;
    }

removeMin()方法涉及到最末和頂部元素替換,重排序的過程也會相對複雜。


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

  1. “既然用陣列實現堆時,使用了陣列進行儲存,為什麼不能直接用這樣的方法來匯入元素↓?”
public void ArrayToHeap(T[] array) {
        tree = array;
        count = tree.length + 1;
    }

後面產生了一系列問題,但是使用書本上的addElement()方法插入時則不會出錯,後來仔細研究addElement()才發現問題所在:直接匯入的陣列不一定符合堆的性質,而使用addElement()方法由於重排序的存在可以很好地解決這一問題。


程式碼託管

(statistics.sh指令碼的執行結果截圖)


上週考試錯題總結

  • Insertion sort is an algorithm that sorts a list of values by repetitively putting a particular value into its final, sorted, position.
    答案:false
    )並不是直接放入最終排序位置。

  • There are only two ways that a tree, or any subtree of a tree, can become unbalanced: through the insertion of a node or through the deletion of a node.
    答案:true
    )書中原話。


學習進度條

程式碼行數(新增/累積) 部落格量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 0/0 1/1 6/6
第二週 771/771 1/2 16/22
第三週 562/1233 1/3 15/37
第四周 1503/2736 2/5 15/52
第五週 1152/3888 1/6 10/62
第六週 787/4675 1/7 10/72
第七週 1214/5889 1/8 9/81
第八週 1534/7423 1/9 9/90

結對互評

唐才銘19
王文彬29

參考資料