实现堆排序,函数void HeapAdjust(SqList &L,int s,int m)为筛选法调整堆,函数void CreatHeap(SqList &L)把无序序列L.r[1…n]建成大根堆,函数void HeapSort(SqList &L)对顺序表L进行堆排序。
函数接口定义:
void HeapAdjust(SqList &L,int s,int m);//筛选法调整堆
void CreatHeap(SqList &L); //把无序序列L.r[1..n]建成大根堆
void HeapSort(SqList &L);//对顺序表L进行堆排序
裁判测试程序样例:
```cpp
#include <iostream>
#define MAXSIZE 1000
using namespace std;
typedef struct
{
int key;
char *otherinfo;
}ElemType;
typedef struct
{
ElemType *r;
int length;
}SqList;
void Create_Sq(SqList &L)
{
int i,n;
cin>>n; //输入的值不大于 MAXSIZE
for(i=1;i<=n;i++)
{
cin>>L.r[i].key;
L.length++;
}
}
void show(SqList L)
{
int i;
for(i=1;i<=L.length;i++)
if(i==1)
cout<<L.r[i].key;
else
cout<<" "<<L.r[i].key;
}
void HeapAdjust(SqList &L,int s,int m);//筛选法调整堆
void CreatHeap(SqList &L); //把无序序列L.r[1..n]建成大根堆
void HeapSort(SqList &L);//对顺序表L进行堆排序
int main()
{
SqList L;
L.r=new ElemType[MAXSIZE+1];
L.length=0;
Create_Sq(L);
HeapSort(L);
show(L);
return 0;
}
/* 请在这里填写答案 */
输入样例:
第一行输入一个数n(输入的值不大于 MAXSIZE)
第二行依次输入n个数
9
30 45 53 78 65 9 12 17 23
输出样例:
输出升序排列的结果
9 12 17 23 30 45 53 65 78
代码长度限制 16KB
时间限制 400ms
内存限制 64MB
代码如下
// 堆化,保持堆的性质
// 从元素L.r[i].key,L.r[lt].key,L.r[rt].key中找出最大的,并将其下标保存在largest中。
// 如果L.r[i].key是最大的,则以i为根的子树成已为最大堆,程序结束。
// 否则,i的某个子节点中有最大元素,则交换L.r[i].key,L.r[largest].key从而使i及其子女满足堆性质。
// 下标为largest的结点在交换后的值为L.r[i].key,以该结点为根的子树又有可能违反最大堆性质。因而要对该子树递归调用HeapAdjust。
void HeapAdjust(SqList &L, int i, int size)
{
int lt = 2*i, rt = 2*i+1;
int largest;
if(lt <= size && L.r[lt].key > L.r[i].key) //右孩子没有超过结点总数,且右孩子大于根节点。
largest = lt; //便把右孩子的下标记下来,给最大值下标
else
largest = i; //否则把根节点的下标记下来,给最大值下标
if(rt <= size && L.r[rt].key > L.r[largest].key) /*再和左孩子的值进行比较。左孩子没有超过结点总数,且左孩子大于最大结点的值*/
largest = rt; //将左孩子下标记下来,给最大值下标
if(largest != i) //如果最大值下标不是根节点,则进行key值的交换
{
int temp = L.r[i].key;
L.r[i].key = L.r[largest].key;
L.r[largest].key = temp;
HeapAdjust(L, largest, size); //继续调用HeapAdjust函数,进行最大堆的排序。
}
}
// 建堆
/*自底而上地调用HeapAdjust来将一个数组a[1..size]变成一个最大堆.一定要自下而上的调用,
才能保证调用较小层次的结点的堆排序算法时,较高层次以及满足堆的性质。否则可能导致中间层次出现最大值。*/
// 注意: [size/2]以后的结点为叶子结点,即已经满足堆的性质
void CreatHeap(SqList &L)
{
for(int i=L.length/2; i>=1; --i) //当为满二叉树时,分支节点数n2,总结点数n=2n2+1,叶子节点数=n/2+1=n2+1
HeapAdjust(L, i, L.length);
}
// 堆排序
// 初始调用CreatHeap将L.r[1..size].key变成最大堆
// 因为数组最大元素在L.r[1].key,则可以通过将L.r[1].key与L.r[size].key互换达到正确位置
// 现在新的根元素破坏了最大堆的性质,所以调用HeapAdjust调整,
// 使L.r[1..size-1].key成为最大堆,L.r[1].key又是L.r[1..size-1].key中的最大元素,
// 将L.r[1].key与L.r[size-1].key互换达到正确位置。
// 反复调用HeapAdjust,使整个数组成从小到大排序。
// 注意: 交换只是破坏了以L.r[1].key为根的二叉树最大堆性质,它的左右子二叉树还是具备最大堆性质。
// 这也是为何在CreatHeap时需要遍历size/2到1的结点才能构成最大堆,而这里只需要堆化L.r[1].key即可。
void HeapSort(SqList &L)
{
CreatHeap(L );
int len = L.length;
for(int i=L.length; i>=2; --i)
{
int temp = L.r[1].key;
L.r[1].key = L.r[i].key;
L.r[i].key = temp; /*因为最大堆只能保证第一个元素L.r[1].key是最大值,不能保证最后一个元素是最小值*/
len--; /*所以只能通过每次把最大值,也就是L.r[1].key放在数组末尾,才能得到从小到大的序列*/
HeapAdjust(L, 1, len); /*不包括已排好序的L.r[len]后面的数组元素,在未排好序的部分做最大堆的算法*/
}
}