在這一篇文章中,首先介紹一下堆的屬性和性質。然後講解一下建堆的過程,最後講解堆排序。
1、堆的介紹
堆的物理存儲結構就是一個一維的數組,其數據結構就是一個完全的二叉樹。需要注意的是堆中的每個結點不需要後繼指針,其父節點和左右孩子結點都可以通過計算得到。假設要計算結點i(i爲數組的下標)的父節點和左右孩子結點,可以使用以下公式計算:
在此計算的都是結點的數組下標,
由於堆的數據結構是一個完全二叉樹,設該完全二叉樹有n個結點。則其內部結點下標分別爲:1,2,。。。
故其葉子結點下標分別爲:
堆高度:就是從根節點到最長葉子結點的距離。包含N個結點的堆高爲:
其次是最大堆和最小堆問題,最大堆就是對任意的父節點的值總是大於或等於孩子節點的值,這樣的話就能保證根節點保存堆中的最大元素。
即:A[parent(i)] >=A[i] (最大堆)
同樣,最小堆就是對任意的父節點的值小於或等於孩子結點的值,這樣就能保證根節點的值最小。
即:A[parent(i)] <=A[i] (最小堆)
一般情況下,最大堆用於堆排序中,最小堆用於優先隊列中。2、建堆
根據堆的性質,我們最終要得到堆的根節點是一個最值,因而,我們需要自底向上進行建堆,若自頂向下建堆的話則不能保證根節點是最值。在此僅討論建立最大堆的情況。
首先我們可以認爲每個葉子結點已經是一個最大堆,然後從最末一個非葉子結點開始進行對調整,以滿足最大堆的性質。直到到達第一個結點即根節點。在建堆中,主要有二個過程,一個是堆調整,另一個是建堆。在此,首先介紹一下對調整的過程,首先,假如要調整的結點爲i,並且結點i的左右孩子已經都是最大堆。於是,我們首先計算A[i],A[ left(i) ],A[ right(i) ]的大小。1)若A[i]最大,則無需調整。2)若A[ left(i) ]最大,則將A[i]與A[ left(i) ]交換,此時最大值成爲了父節點,而A[ i]到了原來的A[ left(i) ]的位置。然後又將A[ i ]與其左右孩子進行比較,直到葉子結點。同樣,若A[right(i)
]最大,其操作同理可得。
void max_heapify(int A[],int i)
{
l=2*i; //l = left(i)
r=2*i+1; //r = right(i)
//heapSize爲堆中實際元素的個數
if(l <= heapSize && A[l] > A[i]) //largest爲i和l中的最大下標值
largest = l;
else largest = i;
if(l <= heapSize && A[r] > A[largest])
largest = r;
if(i != largest){
swap(A[i], A[largest]); //交換 A[i]與 A[largest]
max_heapify(A, largest);
}
}
建堆的代碼如下:
void build_max_heapify(int A[])
{
for(int i=A.length/2; i>=1; i--)
{
max_heapify(A, i);
}
}
簡單估算一下:我們在調用max_heapify的時間複雜度爲:O(lgn),調用build_max_heapify的次數爲:O(n)。因而,整個建堆的時間複雜度爲:O(nlgn)。
不過這個時間複雜度不是漸進緊確的,因爲在調用max_heapify時並不是所有的結點高度都爲lgn。實際上大部分結點的高度都很小,更準確的說,高度爲h的結點個數至多有個,而在高度爲h的結點上運行max_heapify的代價爲:O(h)。因此,我們可以計算build_max_heapify的總代價爲:
最後得到構造一個最大堆的時間複雜度爲:O(n)。即在線性時間內,可以把一個無序數組構造成爲一個最大堆。
3、堆排序
排序思想:首先使用build_max_heapify將數組A[1,2,…,n]建成最大堆,然後將A[1]與A[n]的互換,然後再使用max_heapify調整數組A[1,2,…,n-1]成最大堆,然後將A[1]與A[n-1]互換,依次類推,最終得到一個升序的數組A[1,2,…,n]。void heapSort()
{
build_max_heapify(A);
int heapSize = A.length; //heapSize=A.length-size
while(heapSize > 1)
{
swap(A[1], A[heapSize]); //交換 A[1]與 A[heapSize]
heapSize --;
max_heapify(A,1);
}
}
時間代價分析:build_max_heapify的時間代價是:O(n), 調用了n-1次的max_heapify,每次的時間爲:O(lgn)。故heapSort的總時間複雜度爲:O(nlgn)。不知道公式怎麼加到文章中,這個暫時做成圖片傳上來了,導致文章的排版比較亂!