複習資料結構:排序演算法(六)——堆排序

bigface1234fdfg發表於2015-02-25

    

    對於堆排序,前面一篇博文中已經複習到了堆排序,這裡就簡單介紹一下,並給出核心部分的解釋。


    堆排序是一種不穩定的排序,也是內排序。

    時間複雜度為O(nlogn)。


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


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,則整個排序過程完成。


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



程式碼如下:


#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://blog.csdn.net/puqutogether/article/details/43195703

http://blog.csdn.net/hguisu/article/details/7776068

http://blog.csdn.net/xiazdong/article/details/8462393

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




相關文章