堆排序基礎

首先,推薦你們去看下《算法導論》,那是算法聖經,講得很是詳細,本文中的代碼大部分是將其中的僞代碼用C/C++實現出來ios

雖然書上有堆排序(heapsort)的概念的詳細解釋,網絡上介紹堆排序的講解也基本都有描述,我這仍是將一些基本概念寫出來:算法

:(二叉)堆數據結構是一種數組對象,能夠被視爲一棵徹底二叉樹,樹中的每一個結點與數組中存放該結點值的那個元素對應。以下圖所示:api

 

假設存儲數組下標從1開始,則給定某個結點的標 i, 易得其父結點下標爲 ⌊i / 2⌋, 左兒子結點下標爲 2 * i,右結點下標爲2 * i + 1數組

二叉堆有兩種:最大堆和最小堆(小根堆),上圖即爲最大堆及其數組表示網絡

最大堆:在最大堆中,最大堆特性是指除了根之外的每一個結點 i ,有 A[PARENT( i )] ≥ A[ i ](PARENT(i)是指 i 結點的父結點), 即某個結點的值至可能是和其父結點的值同樣大,這樣,堆中的最大元素就存放在根結點中;而且,在以某一個結點爲根的子樹中,各結點的值都不大於該子樹結點的值數據結構

最小堆:組織方式與最大堆正好相反;最小堆特性就是除了根之外的每一個結點i,有A[PARENT( i )] ≤ A[ i ],最小元素在根部ui

堆排序:堆排序的實現利用了最大堆(最小堆)的「堆的最大(小)元素就存放在根結點中」這一特性,能夠在每次堆化後儘快地找到當前堆的最大(小)元素spa

在堆排序中,一般使用的是最大堆,而最小堆一般在構造優先隊列時使用,關於優先隊列的實現後面的總結中會出現.net

堆排序的運行時間爲O(n lgn),是一種原地排序算法:在任什麼時候候,數組中只有常數個元素存儲在輸入數組之外code


具體實現看如下代碼:

/*
***Author: asd
***Data: 2012/7/13
***blog:http://blog.csdn.net/zhengjj_asd
***HeapSort
*/

#include <iostream>
using namespace std;

//利用異或交換 a, b 的值
#define swap(a, b) { a^= b^= a^= b;}

//輸出 a[1..size] 的值
void arr_display(int *a, int size)
{
	for(int i = 1; i < size; ++ i)
		cout << a[i] << " ";
	cout << a[size] << endl;
}

//調用是假定 a[left], a[right] 爲根的兩棵二叉樹都是已成最大堆
//可是a[i]可能小於它的子節點,違反了最大堆的性質
//Max_Heapify使a[i]在最大堆中「降低」,使以i爲根的子樹成爲最大堆
void Max_Heapify(int *a, int size, int i)
{
	int left = 2 * i;
	int right = 2 * i + 1;
	int largest;
	if(left <= size && a[left] > a[i])
		largest = left;
	else
		largest = i;
	if(right <= size && a[right] > a[largest])
		largest = right;
	if(largest != i)
	{
		swap(a[largest], a[i]);
		Max_Heapify(a, size, largest);
	}
}

//自底向上地將一個數組a[1..n]變成一個最大堆
//在數組a[1..n]中,a[(n / 2) + 1..n]是樹中的葉子
//每一個都是隻含一個元素的堆,對其餘結點(也就是非葉子結點)都調用一次Max_Heapify
void Build_Max_Heap(int *a, int size)
{
	for(int i = size / 2; i >= 1; -- i)
		Max_Heapify(a, size, i);
}

//先將數組a[1..n]用Build_Max_Heap構形成一個最大堆
//由於a[1]爲堆中最大的元素,因此能夠經過其與a[n]交換,使其到達最終正確的位置
//而後在堆中去掉交換後的結點n,由於結點1爲根的子女仍然仍是最大堆
//而交換後的結點1可能就違背了最大堆的性質,只要用Max_Heapify進行維護
//使a[1..n-1]仍然爲最大堆,而後又交換a[1]與a[n-1],再調用Max_Heapify
//重複這個過程可以使堆的大小從n-1一直降到2,這時a[1..n]即爲原數組按非降序排序結果
void HeapSort(int *a, int size)
{
	Build_Max_Heap(a, size);
	cout << "建堆結果...";
	arr_display(a, size);
	int num = size;
	cout << "排序中..." << endl;
	for(int i = size; i >= 2; -- i)
	{
		swap(a[1], a[size]);
		-- size;
		Max_Heapify(a, size, 1);
		cout << "第" << num - size << "步...";
		arr_display(a, num);
	}
}

int main()
{
	int a[50], size;   //size爲輸入規模大小
	cout << "輸入元素個數:";
	cin >> size;
	cout << "輸入各個元素:";
	for(int i = 1; i <= size; ++ i)
		cin >> a[i];
	cout << "排序開始..." << endl;
	HeapSort(a, size);
}

最後,再次提醒,去看看《算法導論》的第六章,其中的內容很是詳細

還有你們若是有什麼問題,能夠留言...