算法導論學習之——堆排序

    在這一篇文章中,首先介紹一下堆的屬性和性質。然後講解一下建堆的過程,最後講解堆排序。


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)。


不知道公式怎麼加到文章中,這個暫時做成圖片傳上來了,導致文章的排版比較亂!


發佈了33 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章