實現堆排序

bigface1234fdfg發表於2015-01-27

實現堆排序

    

1. 堆排序的思想

     堆是一棵完全二叉樹,任何一個節點的val不大於(最小堆)或者不小於(最大堆)其左右孩子節點的關鍵字。


    以最大堆為例,堆排序的基本思想是:


1)將初始待排序關鍵字序列(R1,R2....Rn)構建成大頂堆,此堆為初始的無序區;

2)將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且滿足R[1,2...n-1]<=R[n];

3)由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,......Rn-1)調整為新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。


    其實,堆排序最重要的兩部分就是:初始化堆和調整堆。


我們可以用下圖展示堆排序的過程:

給定一個整形陣列a[]={16,7,3,20,17,8},對其進行堆排序。


1) 構建最大堆;

這一步驟只需要構建一個完全二叉樹即可;


2)初始化最大堆;


這一步驟需要不斷調整,使得堆成為最大堆。

調整從最後一個非葉子節點開始。每次調整都是從父節點、左孩子節點、右孩子節點三者中選擇最大者跟父節點進行交換(交換之後可能造成被交換的孩子節點不滿足堆的性質,因此每次交換之後要重新對被交換的孩子節點進行調整)。


3)排序,繼續調整最大堆;

堆頂20和3交換:


堆頂17和3交換:


堆頂16和3交換:


堆頂8(7)和3交換:


   總的來說,堆排序就是一個不斷調整堆的過程。

    堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從R[1...n]中選擇最大記錄,需比較n-1次,然後從R[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經在前面的n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點儲存了部分前面的比較結果,因此可以減少比較次數。對於n個關鍵字序列,最壞情況下每個節點需比較log2(n)次,因此其最壞情況下時間複雜度為nlogn

    堆排序為不穩定排序,不適合記錄較少的排序。

2. 程式設計實現堆排序


#include<iostream>
#include<algorithm>
using namespace std; 

// 調整堆函式
void HeapAdjust(int *a, int i, int size)  // a:陣列;i:節點index;size:樹的規模
{
	int lchild = 2 * i;   // 節點的左孩子編號
	int rchild = 2 * i + 1;   // 節點的右孩子編號
	int max = i;  //節點編號備份
	if(i <= size/2 - 1)
	{
		if(lchild <= size && a[lchild] > a[max])  // 左孩子比節點值要大
			max = lchild; 
		if(rchild <= size && a[rchild] > a[max])  // 右孩子比節點值要大
			max = rchild; 
		if(max != i)  // 如果上面發生了交換,也就是如果上面有if成立了
		{
			swap(a[i], a[max]);   // 首先要交換二者的真實值,因為上面只是index的交換
			HeapAdjust(a, max, size);  // 其次,需要判斷交換之後還需要重新調整嗎
		}
	}
}

//建立堆函式
void BuildHeap(int *a, int size)  
{
	int i; 
	for(i = size/2 - 1; i >= 0; i--)  // 非葉子節點最大序號值為size/2,需要遍歷所有的節點
	{
		HeapAdjust(a, i, size);   // 調整
	}
}

// 堆排序函式
void HeapSort(int *a, int size)
{
	int i; 
	BuildHeap(a, size); 
	for(i = size; i >= 0; i--)
	{
		swap(a[0], a[i]);  //  交換堆頂和最後一個元素,每次將剩餘元素中的最大者放到最後面
		HeapAdjust(a, 0, i-1);  // 重新調整堆頂節點成為大頂堆,這個時候就要除出最後一個元素,範圍是1~n-1
	}
}

int main()
{
	int a[] = {100, 16, 20, 3, 11, 17, 8};
	int size = 7; 
	HeapSort(a, size); 
	for(int i = 0; i < size; i++)
	{
		cout<<a[i]<<endl; 
	}
	cout<<endl; 

	return 0; 
}



參考連結:

http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html


相關文章