Heap堆的概念,排序,刪除和插入

http://fangjian0423.github.io/2016/04/09/heap-heapsort/

堆的概念:

n個元素序列 { k1, k2, k3, k4, k5, k6 …. kn } 當且僅當滿足以下關系時才會被稱為堆:

ki <= k2i,ki <= k2i+1 或者 ki >= k2i,ki >= k2i+1 (i = 1,2,3,4 .. n/2)

如果數組的下表是從0開始,那么需要滿足

ki <= k2i+1,ki <= k2i+2 或者 ki >= k2i+1,ki >= k2i+2 (i = 0,1,2,3 .. n/2)

比如 { 1,3,5,10,15,9 } 這個序列就滿足 [1 <= 3; 1 <= 5], [3 <= 10; 3 <= 15], [5 <= 9] 這3個條件,這個序列就是一個堆。

所以堆其實是一個序列(數組),如果這個序列滿足上述條件,那么就把這個序列看成堆。

堆的實現通常是通過構造二叉堆,因為二叉堆應用很普遍,當不加限定時,堆通常指的就是二叉堆。

二叉堆的概念:

二叉堆是一種特殊的堆,是一棵完全二叉樹或者是近似完全二叉樹,同時二叉堆還滿足堆的特性:父節點的鍵值總是保持固定的序關系于任何一個子節點的鍵值,且每個節點的左子樹和右子樹都是一個二叉堆。

當父節點的鍵值總是大于或等于任何一個子節點的鍵值時為最大堆。 當父節點的鍵值總是小于或等于任何一個子節點的鍵值時為最小堆。


上圖中的最小堆對應的序列是: [1,3,5,9,10,15] 滿足最小堆的特性(父節點的鍵值小于或等于任何一個子節點的鍵值,并且也滿足堆的性質 [1 <= 3; 1 <= 5], [3 <= 9; 3 <= 10], [5 <= 15])

上圖中的最大堆對應的序列是: [15,10,9,7,5,3] 滿足最大堆的特性(父節點的鍵值大于或等于任何一個子節點的鍵值,并且也滿足堆的性質 [15 >= 10; 15 >= 9], [10 >= 7; 10 >= 5], [9 >= 3])

堆的操作

堆排序

堆排序指的是對堆這種數據結構進行排序的一種算法。其基本思想如下,以最大堆為例:

將數組序列構建成最大堆[ A1, A2, A3 .. An],這個堆是一個剛初始化無序區,同時有序區為空

堆頂元素A1與最后一個元素An進行交換,得到新的有序區[An],無序區變成[A1 … An-1]

交換之后可能導致[A1 … An-1]這個無序區不是一個最大堆,[A1 … An-1]無序區重新調整成最大堆。重復步驟2,A1與An-1進行交換,得到新的有序區[An,An-1],無序區變成[A1 … An-2].. 不斷重復,直到有序區的個數為n-1才結束排序過程

構造堆的過程如下(以最大堆為例):

從最后一個非葉子節點開始調整,遍歷節點和2個子節點,選擇鍵值最大的節點的鍵值代替父節點的鍵值,如果進行了調整,調整之后的兩個子節點可能不符合堆特性,遞歸調整。一直直到調整完根節點。

以序列[3,5,15,9,10,1]為例進行的堆排序:

首先第1步先把數組轉換成完全二叉樹:

最大堆構成

接下來是第2、3步構造有序區和無序區:

最大堆得順序

構造完之后有序區的元素依次是:1,3,5,9,10,15

簡單地使用java寫一下堆排序:

public class HeapSort {

public static void maxHeapify(int[] arr, int size, int index) {

int leftSonIndex = 2 * index + 1;

int rightSonIndex = 2 * index + 2;

int temp = index;

if(index <= size / 2) {

if(leftSonIndex < size && arr[temp] < arr[leftSonIndex]) {

temp = leftSonIndex;

}

if(rightSonIndex < size && arr[temp] < arr[rightSonIndex]) {

temp = rightSonIndex;

}

// 左右子節點的值存在比父節點的值更大

if(temp != index) {

swap(arr, index, temp); // 交換值

maxHeapify(arr, size, temp); // 遞歸調整

}

}

}

public static void heapSort(int[] arr, int size) {

// 構造成最大堆

buildMaxHeap(arr, arr.length);

for(int i = size - 1; i > 0; i --) {

// 先交換堆頂元素和無序區最后一個元素

swap(arr, 0, i);

// 重新調整無序區

buildMaxHeap(arr, i - 1);

}

}

public static void buildMaxHeap(int[] arr, int size) {

for(int i = size / 2; i >= 0; i --) { // 最后一個非葉子節點開始調整

maxHeapify(arr, size, i);

}

}

public static void swap(int[] arr, int i, int j) {

int temp = arr[i];

arr[i] = arr[j];

arr[j] = temp;

}

public static void main(String[] args) {

int[] arr = { 3, 5, 15, 9, 10, 1};

System.out.println("before build: " + Arrays.toString(arr)); // before build: [3, 5, 15, 9, 10, 1]

buildMaxHeap(arr, arr.length);

System.out.println("after build: " + Arrays.toString(arr)); // after build: [15, 10, 3, 9, 5, 1]

heapSort(arr, arr.length);

System.out.println("after sort: " + Arrays.toString(arr)); // after sort: [1, 3, 5, 9, 10, 15]

}

}

添加

在最大堆[ 15,10,9,7,5,3 ]上添加一個新的元素 11 ,執行的步驟如下:

insert new node

刪除

在最大堆[ 15,10,9,7,5,3 ]上刪除元素 10 ,執行的步驟如下:

delete one node
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 排序算法是最基本最常用的算法,不同的排序算法在不同的場景或應用中會有不同的表現,我們需要對各種排序算法熟練才能將它...
    若丶天下閱讀 448評論 0 1
  • 排序算法是最基本最常用的算法,不同的排序算法在不同的場景或應用中會有不同的表現,我們需要對各種排序算法熟練才能將它...
    AlvinL閱讀 71,765評論 64 1,739
  • 簡單 文/初陽 我打算好了, 這一世來的不是太容易, 因此我選擇三處景: 一處走過橋后的回頭; 一處奮力...
    水中卍初陽閱讀 191評論 1 1
  • 天氣 晴 體重 不知道 早 沒吃 午 食堂 米線5元+餅2.5元+果粒橙三塊五 晚 飯館聚餐27元 穿 雪地靴+加...
    Mikako閱讀 165評論 0 0
  • 《紅樓夢》是一部具有世界影響力的小說作品。曹雪芹用超現實手法寫下了一本沒有寫完的書,讓一批又一批的紅學研究者...
    舍得LL閱讀 333評論 0 0