文字描述

  堆排序中,待排序数据同样可以用完全二叉树表示, 完全二叉树的所有非终端结点的值均不大于(或小于)其左、右孩子结点的值。由此,若序列{k1, k2, …, kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

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

  由此,实现堆排序需要解决两个问题:(1)如何由一个无序序列建成一个堆?(2)如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?

  先讨论第(2)个问题,假设有个最大堆(堆顶元素为堆的最大值)输出堆顶元素之后, 以堆中最后一个元素代替之,此时根结点的左、右子树均为堆,则仅需自上至下进行调整即可。称这个自堆顶至叶子的调整过程为“筛选”。

再讨论第(1)个问题,由一个无序序列建成堆的过程就是一个反复”筛选”的过程。若将此序列看成一个完全二叉树,则最后一个非终端结点是第[n/2]个元素,由此“筛选”只需从第[n/2]个元素开始。

示意图

算法分析

  堆排序在树形选择排序上进行了改进, 和树形选择排序比, 堆排序可以减少辅助空间, 避免和”最大值”的冗余比较等优点.

  堆排序在最坏情况下,其时间复杂度也为nlogn。相对于快速排序来说,这是堆排序的最大优点(快速排序最坏情况下时间复杂度为n*n, 但平均性能为nlogn)。

  堆排序只需一个记录大小的辅助空间供交换用。

  堆排序是一种不稳定的排序方法。

  另外,堆排序方法对记录数较少的文件并不提倡使用, 但是对n较大的文件还是很有效的,因为其运行时间主要耗费在建立初始堆和调整新堆时的反复“筛选”上。

代码实现

 #include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*
* double log2(double x); 以2为底的对数
* double ceil(double x); 取上整
* double floor(double x); 取下整
* double fabs(double x); 取绝对值
*/ #define DEBUG #define EQ(a, b) ((a) == (b))
#define LT(a, b) ((a) < (b))
#define LQ(a, b) ((a) <= (b)) #define MAXSIZE 100
#define INF 1000000
typedef int KeyType;
typedef char InfoType;
typedef struct{
KeyType key;
InfoType otherinfo;
}RedType; typedef struct{
RedType r[MAXSIZE+];
int length;
}SqList; void PrintList(SqList L){
int i = ;
printf("下标值:");
for(i=; i<=L.length; i++){
printf("[%d] ", i);
}
printf("\n关键字:");
for(i=; i<=L.length; i++){
if(EQ(L.r[i].key, INF)){
printf(" %-3c", '-');
}else{
printf(" %-3d", L.r[i].key);
}
}
printf("\n其他值:");
for(i=; i<=L.length; i++){
printf(" %-3c", L.r[i].otherinfo);
}
printf("\n\n");
return ;
} //堆采用顺序存储表示
typedef SqList HeapType; /*
*已知H->r[s,...,m]中记录的关键字除H->r[s].key之外均满足的定义
*本汉书调整H-r[s]的关键字,使H->r[s,...,m]成为一个大顶堆(对其中
*记录的关键字而言)
*/
void HeapAdjust(HeapType *H, int s, int m)
{
RedType rc = H->r[s];
int j = ;
//沿key较大的孩子结点向下筛选
for(j=*s; j<=m; j*=){
//j为key较大的纪录的下标
if(j<m && LT(H->r[j].key, H->r[j+].key))
j+=;
//rc应该插入位置s上
if(!LT(rc.key, H->r[j].key))
break;
H->r[s] = H->r[j];
s = j;
}
//插入
H->r[s] = rc;
} /*
* 对顺序表H进行堆排序
*/
void HeapSort(HeapType *H)
{
int i = ;
//把H->r[1,...,H->length]建成大顶堆
for(i=H->length/; i>=; i--){
HeapAdjust(H, i, H->length);
}
#ifdef DEBUG
printf("由一个无序序列建成一个初始大顶堆:\n");
PrintList(*H);
#endif
RedType tmp;
for(i=H->length; i>; i--){
//将堆顶记录和当前未经排序子序列H->r[1,...,i]中最后一个记录相互交换
tmp = H->r[];
H->r[] = H->r[i];
H->r[i] = tmp;
//将H->r[1,...,i-1]重新调整为大顶堆
HeapAdjust(H, , i-);
#ifdef DEBUG
printf("调整1至%d的元素,使其成为大顶堆:\n", i-);
PrintList(*H);
#endif
}
} int main(int argc, char *argv[])
{
if(argc < ){
return -;
}
HeapType H;
int i = ;
for(i=; i<argc; i++){
if(i>MAXSIZE)
break;
H.r[i].key = atoi(argv[i]);
H.r[i].otherinfo = 'a'+i-;
}
H.length = (i-);
H.r[].key = ;
H.r[].otherinfo = '';
printf("输入数据:\n");
PrintList(H);
//对顺序表H作堆排序
HeapSort(&H);
return ;
}

堆排序

运行

内部排序->选择排序->堆排序的更多相关文章

  1. 跳跃空间(链表)排序 选择排序(selection sort),插入排序(insertion sort)

    跳跃空间(链表)排序 选择排序(selection sort),插入排序(insertion sort) 选择排序(selection sort) 算法原理:有一筐苹果,先挑出最大的一个放在最后,然后 ...

  2. 排序 选择排序&&堆排序

    选择排序&&堆排序 1.选择排序: 介绍:选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始 ...

  3. 内部排序->选择排序->树形选择排序

    文字描述 树形选择排序又称锦标赛排序; 比如,在8个运动员中决出前3名至多需要11场比赛, 而不是7+6+5=18场比赛(它的前提是甲胜乙,乙胜丙,则甲必能胜丙) 首先对n个记录的关键字进行两两比较, ...

  4. 内部排序->选择排序->简单选择排序

    文字描述 简单排序的基本思想是:每一趟在n-i+1(i=1,2,…,n)个记录中选取关键字最小的记录作为有序列表中的第i个记录. 示意图 略 算法分析 简单排序算法中,所需进行记录移动的操作次数较少, ...

  5. java实现 排序算法(鸡尾酒排序&选择排序&插入排序&二分插入排序)

    1.鸡尾酒排序算法 源程序代码: package com.SuanFa; public class Cocktial {    public static void main(String[] arg ...

  6. JAVA排序--[选择排序]

    package com.array; public class Sort_Select { /** * 项目名称:选择排序 ; * 项目要求:用JAVA对数组进行排序,并运用选择排序算法; * 作者: ...

  7. C-冒泡排序,选择排序,数组

    ——构造类型 ->数组      ->一维数组      ->相同类型的一组数据      ->类型修饰符--数组名—[数组的元素个数(必须是整型表达式或者是整型常量,不能是变 ...

  8. 排序——选择排序(java描述)

    百度百科的描述如下:选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元 ...

  9. [javaSE] 数组(排序-选择排序)

    两层嵌套循环,外层循环控制次数,内层循环进行比较 for(int x=0;x<arr.length;x++){ for(int y=0;y<arr.length;y++){ if(arr[ ...

随机推荐

  1. ubuntu下使用golang、qml与ubuntu sdk开发桌面应用 (简单示例)

    找了很长时间go的gui库,试了gtk,准备试qt的时候发现了这个qml库,试了下很好用. ##准备工作 **1.Go 1.2RC1** go的版本应该不能低于这个,我是在1.2RC发布当天升级后发现 ...

  2. vue返回上一页面如果没有上一页面返回首页

    methods: { back(){ if (window.history.length <= 1) { this.$router.push({path:'/'}) return false } ...

  3. MyBatis Generator使用com.mysql.cj.jdbc.Driver遇到的问题

    MyBatis Generator使用com.mysql.cj.jdbc.Driver Mybatis Generator 1.3.5 新建了一个decision库,并创建了一张user表 impor ...

  4. python使用上下文对代码片段进行计时,非装饰器

    之前发过了一组常用的装饰器,包括了一个where_is_it_called的装饰器,可以计时和对入参和返回结果,被何处调用进行记录,十分强大. 这是用上下文,上下文的好处是,不需要抽成函数才能计时. ...

  5. [Object Tracking] MeanShift

    使用Opencv中均值漂移meanShift跟踪移动目标 Opencv均值漂移pyrMeanShiftFiltering彩色图像分割流程剖析 Opencv目标跟踪—CamShift算法 MeanShi ...

  6. [JS] ECMAScript 6 - Object : compare with c#

    Ref: 对象的扩展 Outline: 属性的简洁表示法 属性名表达式 方法的 name 属性 Object.is() Object.assign() 属性的可枚举性和遍历 Object.getOwn ...

  7. WPF listbox的分组研究

    1. 初探GroupItem对象 2.ContainerStyle 与 GroupItem的绑定对象 3.Grouping 级联

  8. PySide_Qt文档介绍

    http://qt-project.org/wiki/PySideDocumentation/

  9. libuv示例代码

    https://github.com/nikhilm/uvbook/tree/master/code

  10. HTML5——表单美化

    闲聊: 今天小颖在跟着慕课网学习:表单美化 看完了自己跟着敲了敲,顺便做个笔记嘻嘻,好记性不如烂笔头,脑子记不住,就写成笔记,以后也方便查看,嘻嘻. 正文: 1.表单美化_单选按钮篇 2.表单美化_复 ...