堆排序
- 堆排序
下面讨论利用堆进行排序的方法。可以分两种情况分别讨论:
① 如果初始序列是堆,则可通过反复执行如下操作而最终得到一个有序序列:
输出根:即将根(第一个元素)与当前子序列中的最后一个元素交换。
调整堆:将输出根之后的子序列调整为堆(元素个数比输出前少1个)。
向下筛。
② 如果初始序列不是堆,则首先要将其先建成堆,然后再按 ① 的方式来实现。
现在的问题是:如何由一个无序序列建成一个堆?
向上筛。
事实上,由无序序列建堆可通过反复调用筛选操作来实现。
为此,需满足筛选的条件,即左右子树必须为堆。
因此,建堆过程要从下往上逐棵子树地进行筛选。
从易于编程的角度出发,根的下标自然是按从大到小,即根的下标按照从n/2到1的次序将各子树调整为堆。
即:从最后一棵(最右边)高度为2的子树开始调整为堆。从右往左,自底向上(向总树根)逐层调整为堆。
【例】由初始序列(12,15,30,80,100,46,78,33,90,86,64,55,120,230,45)构建堆。
【解】首先由序列构建一棵完全二叉树,自最右高度为2的子树开始,然后从右往左,自底向上逐层调整为堆。
调整过程见后图。
代码块
#define maxlen 100
#define MaxSize 20
typedef int KeyType; //定义关键字类型
typedef char InfoType[10];
typedef struct //记录类型
{
KeyType key; //关键字项
InfoType data; //其他数据项,类型为InfoType
} RecType; //排序的记录类型定义
class rank
{
public:
rank();
virtual ~rank();
RecType R[MaxSize];
// int data[maxlen];
int high;
void shuru(int x);
void shuchu();
void sift(RecType R[],int low,int high);
void heapsort(RecType R[],int n);
void initlist();
};
#endif
#include "stdafx.h"
#include "rank.h"
#include "iostream.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
rank::rank()
{
}
rank::~rank()
{
}
void rank::initlist()//录入
{
// printf("please input some 数:\n");
int i=1;
// R[i]=0;
while(EOF!=scanf("%d",&R[i])) //输入数
{
i++;
if(getchar()=='\n')
break;
}
high= i-1;
// printf("data[top]= %d\n",data[top]);
}
void rank::shuchu()
{
for (int i=1; i<=high; i++)
printf("%d ",R[i]);
cout<<endl;
}
void rank::sift(RecType R[],int low,int high)
{
int i=low,j=2*i; //R[j]是R[i]的左孩子
RecType temp=R[i];
while (j<=high)
{
if (j<high && R[j].key<R[j+1].key) //若右孩子较大,把j指向右孩子//j变为2i+1
j++; //左孩子小于右孩子时,左右交换(左孩子要大于右孩子)
if (temp.key<R[j].key)//双亲结点小于左孩子时,交换(双亲结点要大于左孩子)
{
R[i]=R[j]; //将R[j]调整到双亲结点位置上
i=j; //修改i和j值,以便继续向下筛选
j=2*i;
}
else break; //筛选结束
}
R[i]=temp;
}
void rank::heapsort(RecType R[],int n)
{
int i;
RecType temp;
for (i=n/2; i>=1; i--) //循环建立初始堆
sift(R,i,n); //调整堆,形成75 57 48 40 19 34 38 11 6 13 9 7
for (i=n; i>=2; i--) //进行n-1次循环,完成推排序
{
temp=R[1]; //将第一个元素同当前区间内R[1]对换
R[1]=R[i];
R[i]=temp; //最大值交换到最后
sift(R,1,i-1); //筛选R[1]结点,得到i-1个结点的堆 //前面的无序区调整为堆
} //调整堆
}
#include "stdafx.h"
#include "rank.h"
#include "iostream.h"
int main(int argc, char* argv[])
{
rank r;
// int x;
cout<<"请随意输入一些数字: ";
r.initlist();
cout<<"数组长度为: "<<r.high<<endl;
cout<<"未排序的结果为: ";
r.shuchu();
r.heapsort(r.R,r.high);
cout<<"堆排序之后的结果为: ";
r.shuchu();
// printf("Hello World!\n");
return 0;
}