堆排序的時間複雜度是,與插入排序相似,堆也具有空間原址性,即任何時候都只需要常數個額外的元素空間儲存臨時資料。
1. 堆簡介:
(1)堆是乙個陣列,表示堆的陣列a包括兩個屬性:a.length表示陣列元素的個數,a.heap-size表示有多少個堆元素儲存在該陣列中。
給定一結點的下標i,可以得到其父結點、左孩子和右孩子的下標:
parent(i)
return
left(i)
return 2i
right(i)
return 2i+1
(2)最大堆性質是指除了根以外的所有結點i都要滿足:a[parent(i)] >=a[i],即某個結點的值最多與其父結點一樣大。
堆中的結點高度為該結點到葉結點最長簡單路徑上邊的數目。包含n個元素的堆看做一棵完全二叉樹時,其堆高度為。
2. 維護堆性質
max-heapify是用於維護最大堆性質的過程,輸入為乙個陣列a和乙個下標i。該過程通過對a[i]的值在最大堆中「逐級下降」,從而使得以下標i為根結點的子樹重新遵循最大堆的性質。
max-heapify(a,i)
l = left(i)
r = right(i)
//選出最大結點,將其下標儲存在largest中
if l <= a.heap-sizeand a[l] > a[i]
largest = l
else largest = i
if r <= a.heap-sizeand a[r] > a[largest]
largest = r
//如果a[i]最大,則以i為根結點的子樹已經是最大堆,程式結束
if largest != i
exchangea[i] with a[largest] //否則交換二值
//交換後,下標為largest的結點的值為原來的a[i],以此節點為根的子樹有可能會//違反最大堆的性質,因此需要對子樹遞迴呼叫
max-heapify(a,largest)
注意該過程的時間複雜度為,即與樹高呈線性關係。
3. 建堆
採用自底向上的方法利用過程max-heapify可將乙個大小為n=a.length的陣列a[1..n]轉換為最大堆。過程build-max-heap對樹中的其他結點都呼叫一次max-heapify。
build-max-heap(a)
a.heap-size = a.length
for i = downto 1 //由於a(+1..n)中的元素都是樹的葉節點
max-heapify(a,i)
注意每一次for迴圈的開始,結點i-1,i-2,…,1都是乙個最大堆的根結點。
4. 堆排序演算法
堆排序利用build-max-heap將輸入陣列a[1..n](n=a.length)建成最大堆,因為陣列中的最大元素總在根結點a[1]中,通過把它與a[n]交換,讓該元素放到正確的位置。此時,從堆中去掉結點n,剩餘的結點中,原來根的孩子仍然是最大堆,而新的根結點可能會違背最大堆的性質,因此,呼叫max-heapfy(a,1),從而在a[1..n-1]上構造乙個新的最大堆。以此不斷重複該過程。
heap-sort(a)
build-max-heap(a)
for i =a.length downto 2
exchange a[1] with a[i]
a.heap-size= a.heap-size – 1
max-heapify(a,1)
注意heap-sort的時間複雜度為。
5. 堆的應用:優先佇列
優先佇列是一種用來維護由一組元素構成的集合s的資料結構,其中每乙個元素都有乙個相關的值,稱為關鍵字。最大優先佇列的應用之一是共享計算機系統的作業排程,而最小優先佇列應用之一是基於事件驅動的模擬器。下面介紹最大優先佇列的集中操作。
heap-maximum(a) //返回最大關鍵字的元素
return a[1]
heap-extract-max(a) //去掉並返回s中具有最大關鍵字的元素
if a.heap-size < 1
error "heap underflow"
max = a[1]
a[1] = a[a.heap-size]
a.heap-size = a.heap-size -1
max-heapify(a,1)
return max
heap-increase-key(a,i,key) //將元素i的關鍵字值增加到key
if key
error"new key"
a[i] = key
while i >1 and a[parent(i)] < a[i]
exchangea[i] with a[parent(i)]
i =parent(i)
max-heap-insert(a,key) //實現insert操作
a.heap-size =a.heap-size + 1
a[a.heap-size]= -
heap-increase-key(a,a.heap-size,key)
下面的程式是實現最大堆排序:
voidbuild_max_heap(int *a,int len);
voidheap_sort(int *a,int len);
#include
voidexchange(int *a,int i,int j)
intleft_child(int i)
intright_child(int i)
voidmax_heapify(int *a,int len,int index)
if ((r < len) && (a[r] >a[largest]))
if (largest != index)
}
intmain() ;
exchange(source,0,1);
printf("%d%d",source[0],source[1]);
printf("\n");
int i;
heap_sort(source,sizeof(source)/sizeof(source[0]));
for(i=0;i
printf("\n"); }
voidbuild_max_heap(int *a,int len)
for (i=0;i
printf("\n"); }
voidheap_sort(int *a,int len)
}
演算法導論 6 堆排序
堆的分類 最大堆性質 高度 對於堆的一些基本操作 偽 描述 實現 max heapify python實現 123 4567 891011 1213 def max heapify i print max heapify i l left i r right i if l heap size and...
演算法導論之堆排序
堆排序主要是先建堆,轉化為最大堆,每次把最大的乙個 即最大堆的根節點 和最後乙個交換,這樣每次都把當前最大的乙個放到了最後。堆排序演算法中,最關鍵的就是構造初始堆。需要編寫乙個維護大頂堆性質的函式max heapify。當輸入乙個陣列l和乙個下標i,然後呼叫max heapify時,比較l i l ...
演算法導論之堆排序
二叉 堆,是乙個陣列,可以被看成乙個近似的完全二叉樹,樹上的每乙個節點對應於陣列中的乙個元素。除了最底層之外,該樹是完全充滿的,而且是從左向右填充,a.length表示陣列元素的個數,樹的根結點是a 1 這樣給定乙個節點的下標i,我們很容易計算出其父節點 i 2 左子女 2 i 右子女 2 i 1 ...