堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
若在输出堆顶的最小值之后,使得剩余n-1个元素的序列重又建成一个堆,则得到n个元素中的次小值。如此反复执行,便能得到一个有序序列,这个过程称之为堆排序。
由此可知,实现堆排序需要解决两个问题:
- 如何由一个无序序列建成一个堆?
如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?
下面首先图示建初始堆:
下面首先图示调整堆:
好啦,下面演示代码:
首先是头文件data.h
#define MAXSIZE 20 // 一个用作示例的小顺序表的最大长度
typedef int KeyType; // 定义关键字类型为整型
typedef int InfoType; // 定义数据项类型为整型
typedef int ElemType; // 定义元素类型为整型
typedef int InfoType; // 定义其它数据项的类型
struct RedType // 记录类型
{
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项,具体类型在主程中定义
};
struct SqList // 顺序表类型
{
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length; // 顺序表长度
};
typedef SqList HeapType; // 堆采用顺序表存储表示
bool LT(int a,int b)
{
if(a>b)
return true;
else
{
return false;
}
}
接下来是heapsort.cpp
// c10-1.h 待排记录的数据类型
#include<stdio.h>
#include<stdlib.h>
#include"data.h"
#include<iostream>
using namespace std;
void HeapAdjust(HeapType &H,int s,int m)
{ // 已知H.r[s..m]中记录的关键字除H.r[s].key之外均满足堆的定义,本函数
// 调整H.r[s]的关键字,使H.r[s..m]成为一个大顶堆(对其中记录的关键字而言)
RedType rc;
int j;
rc=H.r[s];
for(j=2*s;j<=m;j*=2)
{ // 沿key较大的孩子结点向下筛选
if(j<m&<(H.r[j].key,H.r[j+1].key))
++j;// j为key较大的记录的下标
if(!LT(rc.key,H.r[j].key))
break; // rc应插入在位置s上
H.r[s]=H.r[j];
s=j;
}
H.r[s]=rc; // 插入
}
void HeapSort(HeapType &H)
{ // 对顺序表H进行堆排序。算法10.11
RedType t;
int i;
for(i=H.length/2;i>0;--i) // 把H.r[1..H.length]建成大顶堆
HeapAdjust(H,i,H.length);
for(i=H.length;i>1;--i)
{ // 将堆顶记录和当前未经排序子序列H.r[1..i]中最后一个记录相互交换
t=H.r[1];
H.r[1]=H.r[i];
H.r[i]=t;
cout<<"("<<t.key<<","<<t.otherinfo<<")"<<endl;;
HeapAdjust(H,1,i-1); // 将H.r[1..i-1]重新调整为大顶堆
}
}
void print(HeapType H)
{
int i;
for(i=1;i<=H.length;i++)
printf("(%d,%d)",H.r[i].key,H.r[i].otherinfo);
printf("\n");
}
#define N 8
void main()
{
RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
// RedType d[N]={{8,1},{23,2},{76,3},{34,4},{23,5},{87,6},{65,7},{92,8}};
HeapType h;
int i;
for(i=0;i<N;i++)
h.r[i+1]=d[i];
h.length=N;
printf("排序前:\n");
print(h);
cout<<endl<<"依次输出堆顶元素";
HeapSort(h);
printf("\n排序后:\n");
print(h);
system("pause");
}
下面是演示结果
从这里看来貌似堆排序是稳定的,其实不然,堆排序是不稳定的
下面举反例:
RedType d[N]={{8,1},{23,2},{76,3},{34,4},{23,5},{87,6},{65,7},{92,8}};
排序后的结果当然就是:
{23,5}到了{23,2}前面。
图示之
这一次我们没有像上次一样几个内部排序算法一起比较,但是这里还是给出一般结论吧。
这里的参考书籍也是严奶奶的《数据结构》,下一次希望和大家一起学习
**基数排序**O(∩_∩)O哈哈~。