2018年學習總結博客總目錄:第一週 第二週 第三週 第四周 第五週 第六週 第七週 第八週
html
1.堆(heap)是具備兩個附加屬性的一棵二叉樹:
(1)它是一棵徹底二叉樹,即該樹是平衡的,且底層全部葉子都位於樹的左邊。
(2)最小堆:對每一結點,它小於或等於其左孩子和右孩子。
最大堆:對每一結點,它大於或等於其左孩子和右孩子。
java
2.堆的接口定義及其方法實現:
(1)addElement:將給定元素添加到該堆中;
對於新插入的結點而言,它只存在一個正確位置,且它要麼是h層左邊的下一個空位置,要麼是h+1層左邊的第一個位置(若是h層是滿的的話)
(2)removeMin:刪除堆的最小元素;
刪除掉根結點,要找一個元素來替代它,則要維持樹的完整性,那麼只有一個能替換根的合法元素,且它是存儲在樹中最末一片葉子上的元素。
(3)findMin:返回一個指向堆中最小元素的引用。
返回存儲在根處的元素便可。node
3.使用堆:優先級隊列
優先級隊列:(1)具備更高優先級的項目在先(2)具備相同優先級的項目採用先進先出的方法來肯定其排序。git
4.用鏈表實現堆算法
(3)removeMin操做
①用存儲在最末結點處的元素替換存儲在根處的元素(這一步至關於已經把最小元素刪除)
②將最末結點處的元素刪除,即將最末結點處的父結點的左孩子或右孩子設爲空
③更新最後結點的引用指向
④對堆進行重排序,從根開始,往下進行api
findMin操做
返回一個指向存儲在堆根處元素的引用數組
5.用數組實現堆
在二叉樹的數組實現中,樹的根位於位置0處,對於每一結點n,n的左孩子將位於數組的2n+1位置處,n的右孩子將位於數組的2(n+1)位置處。安全
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中,有六個不一樣的地方能夠存儲數據:
- 寄存器(register)。這是最快的存儲區,由於它位於不一樣於其餘存儲區的地方——處理器內部。可是寄存器的數量極其有限,因此寄存器由編譯器根據需求進行分配。你不能直接控制,也不能在程序中感受到寄存器存在的任何跡象。
- 堆棧(stack)。位於通用RAM中,但經過它的「堆棧指針」能夠從處理器哪裏得到支持。堆棧指針若向下移動,則分配新的內存;若向上移動,則釋放那些內存。這是一種快速有效的分配存儲方法,僅次於寄存器。建立程序時候,JAVA編譯器必須知道存儲在堆棧內全部數據的確切大小和生命週期,由於它必須生成相應的代碼,以便上下移動堆棧指針。這一約束限制了程序的靈活性,因此雖然某些JAVA數據存儲在堆棧中——特別是對象引用,可是JAVA對象不存儲其中。
- 堆(heap)。一種通用性的內存池(也存在於RAM中),用於存放因此的JAVA對象。堆不一樣於堆棧的好處是:編譯器不須要知道要從堆裏分配多少存儲區域,也沒必要知道存儲的數據在堆裏存活多長時間。所以,在堆裏分配存儲有很大的靈活性。當你須要建立一個對象的時候,只須要new寫一行簡單的代碼,當執行這行代碼時,會自動在堆裏進行存儲分配。固然,爲這種靈活性必需要付出相應的代碼。用堆進行存儲分配比用堆棧進行存儲存儲須要更多的時間。
- 靜態存儲(static storage)。這裏的「靜態」是指「在固定的位置」。靜態存儲裏存放程序運行時一直存在的數據。你可用關鍵字static來標識一個對象的特定元素是靜態的,但JAVA對象自己歷來不會存放在靜態存儲空間裏。
- 常量存儲(constant storage)。常量值一般直接存放在程序代碼內部,這樣作是安全的,由於它們永遠不會被改變。有時,在嵌入式系統中,常量自己會和其餘部分分割離開,因此在這種狀況下,能夠選擇將其放在ROM中
- 非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這個數組實現的堆來構造隊列,但在刪除一個元素以後元素個數沒有變化
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行。
解析:一個最小堆在其根結點存儲的是其最小元素,同時它的兩個孩子也是最小堆。作題時沒有認真看清楚,只關注了後半部分,致使錯誤。
解析:又是隻關注了後半部分,前半部分的說法是錯誤的,堆不是一個二叉搜索樹,而是一個二叉平衡樹。
解析:樹的主要應用之一是爲其餘集合提供高效的實現,而非簡單的實現。簡單≠高效。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 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 | 堆、最小堆 |