内部排序——堆排序初探

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

堆

若在输出堆顶的最小值之后,使得剩余n-1个元素的序列重又建成一个堆,则得到n个元素中的次小值。如此反复执行,便能得到一个有序序列,这个过程称之为堆排序。

由此可知,实现堆排序需要解决两个问题:

  1. 如何由一个无序序列建成一个堆?
  2. 如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?

    下面首先图示建初始堆:
    初始堆

下面首先图示调整堆:
调整堆

好啦,下面演示代码:
首先是头文件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&&LT(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哈哈~。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值