堆排序
堆是具有下列性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱爲大頂堆(也叫最大堆);或者每個結點的值都小於或等於其左右孩子結點的值,稱爲小頂堆(也叫最小堆)。
最小堆和最大堆如下圖示:
可以發現:根結點一定是堆中所有結點最大(小)者。
堆排序的基本思想(以大頂堆爲例):將待排序的序列構成一個大頂堆。此時,整個序列的最大值就是堆頂的根結點。將它移走(其實就是將其與堆數組的末尾元素交換,此時末尾元素就是最大值),然後將剩餘的 n-1 個序列重新構成一個堆,這樣就會得到 n 個元素中的次大值。如此反覆執行,便能得到一個有序序列了。
堆排序的思想用例圖解釋如下:
1. 初始最小堆的建立過程(自下向上逐步調整爲最小堆)
具體代碼如下:
1、排序前的一些準備工作,建立合適的排序需要的結構。
/********* 排序用到的結構 頭文件sort_struct.h ************/
#define MAXSIZE 100 //要排序數組個數最大值
class SqList{
public:
int r[MAXSIZE+1];
int length;
};
/* 交換L中數組r下標爲i和j的值 */
void swap(SqList *L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
/* 顯示數組內容 */
void showSqList(SqList *L)
{
for(int i=1;i<=L->length;i++)
std::cout<<L->r[i]<<" ";
std::cout<<std::endl;
}
2、編寫主文件,實現排序與測試。
/********* C++堆排序算法 ************/
#include<iostream>
#include<time.h>
#include"sort_struct.h"
using namespace std;
/* 本函數調整L->r[s]的關鍵字,使L->r[s...m]成爲一個大頂堆 */
void HeapAdjust(SqList *L,int s,int m)
{
int temp,j;
temp = L->r[s];
for(j=2*s;j<=m;j*=2) //沿關鍵字較大的孩子結點向下篩選
{
if(j<m && L->r[j]<L->r[j+1])
++j; //j爲關鍵字中較大的孩子結點的下標
if(temp>=L->r[j]) //如果關鍵字均大於孩子結點,跳出
break;
L->r[s] = L->r[j]; //否則交換關鍵字與較大孩子結點的內容
s = j;
}
L->r[s] = temp; //完成插入
}
/* 對順序表L進行堆排序 */
void HeapSort(SqList *L)
{
int i;
for (i=L->length/2;i>0;i--) //把L中的r構建成一個大頂堆
HeapAdjust(L,i,L->length);
for (i=L->length;i>1;i--)
{
swap(L,1,i); //將堆頂記錄和當前未經排序子序列的最後一個記錄交換
HeapAdjust(L,1,i-1); //將L->r[1...i-1]重新調整爲大頂堆
}
}
int main()
{
int num[] = {0,50,30,25,15,84,56,34,99,54,111,24,43,6,62,124};
SqList *L = new SqList;
L->length = sizeof(num)/sizeof(int)-1;
for(int i=1;i<=L->length;i++)
L->r[i] = num[i];
cout<<"排序前:";
showSqList(L);
clock_t start = clock();
HeapSort(L);
clock_t end = clock();
double time = ((double)(start-end)) / (double)CLOCKS_PER_SEC * 1000;
cout<<"排序後:";
showSqList(L);
cout<<"耗時:"<<time<<"ms"<<endl;
return 0;
}
運行結果如下:
由於待排序樣本太少,耗時顯示爲0。