20172302 《Java軟件結構與數據結構》第八週學習總結


2018年學習總結博客總目錄:第一週 第二週 第三週 第四周 第五週 第六週 第七週 第八週
html


教材學習內容總結

第十二章 優先隊列與堆

1.堆(heap)是具備兩個附加屬性的一棵二叉樹:
(1)它是一棵徹底二叉樹,即該樹是平衡的,且底層全部葉子都位於樹的左邊。
(2)最小堆:對每一結點,它小於或等於其左孩子和右孩子。
最大堆:對每一結點,它大於或等於其左孩子和右孩子。
java

  • 接下來所討論內容是關於最小堆的。

2.堆的接口定義及其方法實現:
(1)addElement:將給定元素添加到該堆中;
       對於新插入的結點而言,它只存在一個正確位置,且它要麼是h層左邊的下一個空位置,要麼是h+1層左邊的第一個位置(若是h層是滿的的話)
(2)removeMin:刪除堆的最小元素;
       刪除掉根結點,要找一個元素來替代它,則要維持樹的完整性,那麼只有一個能替換根的合法元素,且它是存儲在樹中最末一片葉子上的元素。
(3)findMin:返回一個指向堆中最小元素的引用。
       返回存儲在根處的元素便可。node

3.使用堆:優先級隊列
優先級隊列:(1)具備更高優先級的項目在先(2)具備相同優先級的項目採用先進先出的方法來肯定其排序。git

4.用鏈表實現堆算法

  • (1)HeapNode類
    繼承自BinaryTreeNode類,在其基礎上添加父結點及其set方法。
  • (2)addElement操做
    ①要添加一個元素,首先有最後一個結點的引用,要去獲得新的最後一個結點的父結點
    ②而後將元素添加至最後結點,並更新最後結點的引用
    ③重新的最後結點處往上進行重排序,以保持其排序屬性
  • (3)removeMin操做
    ①用存儲在最末結點處的元素替換存儲在根處的元素(這一步至關於已經把最小元素刪除)
    ②將最末結點處的元素刪除,即將最末結點處的父結點的左孩子或右孩子設爲空
    ③更新最後結點的引用指向
    ④對堆進行重排序,從根開始,往下進行api

  • findMin操做
    返回一個指向存儲在堆根處元素的引用數組

5.用數組實現堆
       在二叉樹的數組實現中,樹的根位於位置0處,對於每一結點n,n的左孩子將位於數組的2n+1位置處,n的右孩子將位於數組的2(n+1)位置處。安全

  • (1)addElement操做
    ①在恰當位置處添加新結點
    ②對堆進行重排序以維持其排序屬性
    ③將count值遞增1
  • (2)removeMin操做
    ①用存儲在最末元素處的元素替換存儲在根處的元素
    ②對堆進行重排序,返回初始的根元素
    ③將原來的最末元素設爲null,並將count值減1
  • (3)findMin操做
    返回數組的0位置處的元素

6.使用堆:堆排序
       a.將無需序列構建成一個堆,根據升序降序需求選擇大頂堆或小頂堆;
       b.將堆頂元素與末尾元素交換,將最大元素"沉"到數組末端;
       c.從新調整結構,使其知足堆定義,而後繼續交換堆頂元素與當前末尾元素,反覆執行調整+交換步驟,直到整個序列有序。數據結構

  • 使用:將列表中的每一個元素添加進堆裏,而後一次刪除一個元素ide

  • 複雜度分析:對於任一給定的結點,插入到堆的複雜度都是O(logn),所以n個結點的插入複雜度將是O(nlogn),而對於刪除一個結點的複雜度也是O(logn),所以對n個結點的刪除也將會是O(nlogn)。對於堆排序算法,咱們要執行addElement操做和removeMin操做各n次,所以最終的複雜度將是2×n×logn,即O(nlogn)。

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

  • 問題1:一個疑問,以前學習棧的時候,常常會提到堆棧這個概念,那麼堆、堆棧、棧分別是什麼,區別與聯繫?

  • 問題1解決方案:查找資料,我才發現,堆、棧、堆棧它們在這裏不是指數據結構,而是Java中的存儲結構。

    在JAVA中,有六個不一樣的地方能夠存儲數據:
    1. 寄存器(register)。這是最快的存儲區,由於它位於不一樣於其餘存儲區的地方——處理器內部。可是寄存器的數量極其有限,因此寄存器由編譯器根據需求進行分配。你不能直接控制,也不能在程序中感受到寄存器存在的任何跡象。
    2. 堆棧(stack)。位於通用RAM中,但經過它的「堆棧指針」能夠從處理器哪裏得到支持。堆棧指針若向下移動,則分配新的內存;若向上移動,則釋放那些內存。這是一種快速有效的分配存儲方法,僅次於寄存器。建立程序時候,JAVA編譯器必須知道存儲在堆棧內全部數據的確切大小和生命週期,由於它必須生成相應的代碼,以便上下移動堆棧指針。這一約束限制了程序的靈活性,因此雖然某些JAVA數據存儲在堆棧中——特別是對象引用,可是JAVA對象不存儲其中。
    3. 堆(heap)。一種通用性的內存池(也存在於RAM中),用於存放因此的JAVA對象。堆不一樣於堆棧的好處是:編譯器不須要知道要從堆裏分配多少存儲區域,也沒必要知道存儲的數據在堆裏存活多長時間。所以,在堆裏分配存儲有很大的靈活性。當你須要建立一個對象的時候,只須要new寫一行簡單的代碼,當執行這行代碼時,會自動在堆裏進行存儲分配。固然,爲這種靈活性必需要付出相應的代碼。用堆進行存儲分配比用堆棧進行存儲存儲須要更多的時間。
    4. 靜態存儲(static storage)。這裏的「靜態」是指「在固定的位置」。靜態存儲裏存放程序運行時一直存在的數據。你可用關鍵字static來標識一個對象的特定元素是靜態的,但JAVA對象自己歷來不會存放在靜態存儲空間裏。
    5. 常量存儲(constant storage)。常量值一般直接存放在程序代碼內部,這樣作是安全的,由於它們永遠不會被改變。有時,在嵌入式系統中,常量自己會和其餘部分分割離開,因此在這種狀況下,能夠選擇將其放在ROM中
    6. 非RAM存儲。若是數據徹底存活於程序以外,那麼它能夠不受程序的任何控制,在程序沒有運行時也能夠存在。
      就速度來講,有以下關係: 寄存器 < 堆棧 < 堆 < 其餘

(1)new 的對象是存儲在堆中的:
String s1 = "china";
String s2 = "china";
String s3 = "china";
String ss1 = new String("china");
String ss2 = new String("china");
String ss3 = new String("china");


(2)對於基礎類型的變量和常量:變量和引用存儲在棧中,常量存儲在常量池中。
int i1 = 9;
int i2 = 9;
int i3 = 9;
public static final int INT1 = 9;
public static final int INT2 = 9;
public static final int INT3 = 9;

(3)堆棧:JVM 中的堆棧
JVM是基於堆棧的虛擬機.JVM爲每一個新建立的線程都分配一個堆棧.也就是說,對於一個Java程序來講,它的運行就是經過對堆棧的操做來完成的。堆棧以幀爲單位保存線程的狀態。JVM對堆棧只進行兩種操做:以幀爲單位的壓棧和出棧操做。

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

  • 問題1:在作PP12.1時,我使用的是ArrayHeap這個數組實現的堆來構造隊列,但在刪除一個元素以後元素個數沒有變化

  • 問題1解決方案:先看了一遍本身寫的HeapQueue類沒有問題後,就從書上ArrayHeap類找問題,
public T removeMin() throws EmptyCollectionException 
    {
        if (isEmpty())
            throw new EmptyCollectionException("ArrayHeap");

        T minElement = tree[0];
        tree[0] = tree[count-1];
        heapifyRemove();
        count--;
    modCount--;

        return minElement;
    }

       這是書上的代碼,它在把堆的最後一個元素挪至第一位置後,並對進行重排序後,沒有把這個最後一個元素給刪掉,所以致使了這個問題,因而在這段代碼以後加上tree[count] =null;便可解決問題。
       那天寫着光記着改了書上的錯誤了,沒有把隊列這個類的方法所有實現,後面經譚鑫提醒,才發現本身toString方法尚未修改,只是super.toString()了。在實現toString時,應該把這個最小堆按照層序輸出就能夠了,可是這樣仍是存在一個就是,一旦有一個元素出隊了,那麼再去用層序輸出就不會是它本隊列該有的順序了。因而,有一個想法就是把toString方法改寫爲把每個元素出隊再入隊這樣輸出出來,這樣可能在時間複雜度上會變得比較高,但還沒想到更好的解決辦法。

public String toString()
    {
        String result = "";
        int x = size();
        for(int i=0;i<x;i++)
        {
            T t = dequeue();
            result += t+" ";
            enqueue(t);
        }

        return  result;
    }

代碼託管

       上週代碼行數爲13751行,如今爲15816行,本週2065行。

上週考試錯題總結

  • 錯題1.A minheap stores its largest element at the root of the binary tree, and both children of the root of a minheap are also minheaps.(×
  • 解析:一個最小堆在其根結點存儲的是其最小元素,同時它的兩個孩子也是最小堆。作題時沒有認真看清楚,只關注了後半部分,致使錯誤。

  • 錯題2:Since a heap is a binary search tree, there is only one correct location for the insertion of a new node, and that is either the next open position from the left at level h or the first position on the left at level h+1 if level h is full.(×
  • 解析:又是隻關注了後半部分,前半部分的說法是錯誤的,堆不是一個二叉搜索樹,而是一個二叉平衡樹。

  • 錯題3:One of the uses of trees is to provide simpler implementations of other collections.(×
  • 解析:樹的主要應用之一是爲其餘集合提供高效的實現,而非簡單的實現。簡單≠高效。

結對及互評

  • 本週結對學習狀況
    • 20172308
    • 博客中值得學習的或問題:本週結對夥伴博客內容很是充實,教材內容總結面面俱到,教材中的問題總結也很詳細,完整記錄了查找資料和學習的過程。
    • 結對學習內容:第十二章——堆

其餘(感悟、思考等)

感悟

  • 本週堆這一章內容是先聽老師講了一遍,而後才課下學,這一章書上的內容學起來難度不算大,主要的時間都花在了實驗上。

學習進度條

代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 0/0 1/1 15/15
第二週 572/572 1/2 16/31
第三週 612/1184 1/3 13/44
第四周 1468/2652 2/5 13/57
第五週 1077/3729 1/6 14/71 初步理解各個排序算法
第六週 1087/4816 1/7 17/88 認識樹結構
第七週 1252/6068 1/8 19/107 平衡二叉樹、AVL樹、紅黑樹
第八週 2065/8133 2/10 17/124 堆、最小堆

參考資料

相關文章
相關標籤/搜索