昨天老师讲了最后一个内部排序方法:堆排序。刚开始听的时候,比较晕。回来自己想了一会儿,豁然开朗...呵呵。真是佩服那些做算法研究的人。牛X。
堆:假设为大根堆,则 a[i] >= max{ a[2i+1], a[2i+2] } , a[i] 为 parent, a[2i+1], a[2i+2] 为其左/右儿子。
堆排序: 选择排序的优化。逻辑抽象(顺序地为数组元素下标编号)出一颗完全二叉树(自上而下 && 从左到右, 除最后一层叶子外,其余都为满树)。然后循环取出根节点+调节堆。堆排序在最坏情况下的时间复杂度为 nlg(n),而且其空间利用率相对高,除了一个temp外,几乎没有花费另外的存储空间,这点远远好于归并排序。
堆排序在一维简单数组上的实现:
#include <iostream>
using namespace std;
// Pre: low 到 high 之间除了low 以外都符合堆。
// Post: low 到 high 都满足堆条件。
void heapify( int a[], int low, int high )
{
bool fini=false; // fini 代表 finished, bool flag。
int temp = a[low]; int i = low; // 把 a[low], 和 low 先备份一下。
int j = 2*low +1;
// 找到第一个<= a[low] 的 位置。
while( j<=high && !fini )
{
if( j<high && a[j]<a[j+1] )
j++;
if( a[j] <= a[low] )
fini = true;
else { a[i]=a[j]; i=j; j = 2*j+1; }
}
a[i] = temp; // not a[j] = temp;
}
void heap_sort( int a[], int n ) // l_n : stands for last_unsorted.
{
// for 循环建堆。 没有必要从 n-1 开始,因为叶子肯定是满足堆结构的,我们从第一个“可能”不满足对结构的位置(n/2 -1 开始)
for( int i= n/2 -1; i>=0; --i )
heapify( a, i, n-1 );
for( int l_n = n-1; l_n >=1 ; --l_n )
{
swap( a[0], a[l_n] );
heapify( a, 0, l_n-1 );
}
}
void main()
{
int a[5]= { 2, 1, 7, 9, 7 };
heap_sort( a, 5 );
for( int i =0; i<5; ++i )
cout<<a[i]<<" "<<flush;
cout<<endl;
cin.get();
}