堆排序原理及算法实现(最大堆)

堆排序

       堆排序是利用堆的性质进行的一种选择排序。下面先讨论一下堆。

1.堆

  堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

  Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]

  即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。

  堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

2.堆排序的思想

   利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。

    其基本思想为(大顶堆):

    1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无须区;

    2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n]; 

    3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

    操作过程如下:

     1)初始化堆:将R[1..n]构造为堆;

     2)将当前无序区的堆顶元素R[1]同该区间的最后一个记录交换,然后将新的无序区调整为新的堆。

    因此对于堆排序,最重要的两个操作就是构造初始堆和调整堆,其实构造初始堆事实上也是调整堆的过程,只不过构造初始堆是对所有的非叶节点都进行调整。

    下面举例说明:

     给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。

    首先根据该数组元素构建一个完全二叉树,得到

 然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下:

20和16交换后导致16不满足堆的性质,因此需重新调整

这样就得到了初始堆。

即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。有了初始堆之后就可以进行排序了。

此时3位于堆顶不满堆的性质,则需调整继续调整

这样整个区间便已经有序了。
从上述过程可知,堆排序其实也是一种选择排序,是一种树形选择排序。只不过直接选择排序中,为了从R[1...n]中选择最大记录,需比较n-1次,然后从R[1...n-2]中选择最大记录需比较n-2次。事实上这n-2次比较中有很多已经在前面的n-1次比较中已经做过,而树形选择排序恰好利用树形的特点保存了部分前面的比较结果,因此可以减少比较次数。对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为nlogn。堆排序为不稳定排序,不适合记录较少的排序。

测试程序

/*堆排序(大顶堆) 2011.9.14*/ #include <iostream>
#include<algorithm>
using namespace std;void HeapAdjust(int *a,int i,int size)  //调整堆 
{int lchild=2*i;       //i的左孩子节点序号 int rchild=2*i+1;     //i的右孩子节点序号 int max=i;            //临时变量 if(i<=size/2)          //如果i不是叶节点就不用进行调整 {if(lchild<=size&&a[lchild]>a[max]){max=lchild;}    if(rchild<=size&&a[rchild]>a[max]){max=rchild;}if(max!=i){swap(a[i],a[max]);HeapAdjust(a,max,size);    //避免调整之后以max为父节点的子树不是堆 }}        
}void BuildHeap(int *a,int size)    //建立堆 
{int i;for(i=size/2;i>=1;i--)    //非叶节点最大序号值为size/2 {HeapAdjust(a,i,size);    }    
} void HeapSort(int *a,int size)    //堆排序 
{int i;BuildHeap(a,size);for(i=size;i>=1;i--){//cout<<a[1]<<" ";swap(a[1],a[i]);           //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面 //BuildHeap(a,i-1);        //将余下元素重新建立为大顶堆 HeapAdjust(a,1,i-1);      //重新调整堆顶节点成为大顶堆}
} int main(int argc, char *argv[])
{//int a[]={0,16,20,3,11,17,8};int a[100];int size;while(scanf("%d",&size)==1&&size>0){int i;for(i=1;i<=size;i++)cin>>a[i];HeapSort(a,size);for(i=1;i<=size;i++)cout<<a[i]<<" ";cout<<endl;}return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/510178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hbase Region in transition (RIT) 异常解决

查看Hbase状态&#xff0c;突然发现出现了RIT&#xff0c;并且很长时间了~ 查看了一些相关RIT介绍 &#xff08;部分介绍和Hbase2.0不同&#xff0c;如&#xff1a;RIT状态信息2.0已不在zookeeper保存&#xff09; https://mp.weixin.qq.com/s?__bizMzU5OTQ1MDEzMA&mid224…

邻接表的构建、DFS、BFS搜索

接着上次的文章“图的构建&#xff08;邻接链表法&#xff09;”&#xff0c;邻接链表法构建图相对来说比较简单&#xff0c;并且遍历起来也相对简单&#xff0c;但是要是动态添加图的节点和图的边&#xff0c;则是实在不方便&#xff0c;不过现在不管那么多&#xff0c;今天的…

Storm性能简单测试

看了很多关于Storm性能的文章&#xff0c;说法不一&#xff0c;自己根据实际业务测一下是否能满足自身要求&#xff08;只做了简单集群和代码调优&#xff09; 场景&#xff1a;kafka消费数据标准化后存储到Hbase中 服务器资源&#xff1a;两台32G内存做Supervisor 使用资源平…

Hbase Shell 介绍

目录 Scan 创建表 Count 清空表数据 删除数据 删除表 删除列簇 判断表是否为‘enable’ 插入 Region管理 Scan 查询某个表某个列的数据&#xff1a; scan tableName,{COLUMN>列族&#xff1a;列,LIMIT>需要查看条数} 指定开始Rowkey查询 scan tableName,{STARTRO…

拓扑排序 详解 + 并查集 详解 + 最小生成树详解

若您发现本文有什么错误&#xff0c;请联系我&#xff0c;我会及时改正的&#xff0c;谢谢您的合作&#xff01; 本文为原创文章&#xff0c;转载请注明出处 本文链接 &#xff1a; http://www.cnblogs.com/Yan-C/p/3943940.html 。 哎呀&#xff0c;好久了啊&#xff0c;想…

Impala Shell 简单命令

目录 1.更新元数据 2.对查询结果去格式化 3.查询结果存储到文件 4.去格式化后指定分隔符 5.-p或者--show-profiles:显示查询的执行计划(与EXPLAIN语句输出相同)和每个查询语句底层的执行步骤的详细信息. 6.指定主机名连接 (-i) 7.执行查询语句 8.指定脚本文件执行SQL …

CDH邮件预警

转载自&#xff1a;http://blog.51cto.com/feature09/2055835 在CDH的7180页面找到Cloudera Managerment Service 如图所示&#xff1a; 在Configuration中&#xff0c;搜索alert 设置接收信息的邮箱。 设置内容都在图片上&#xff1a; 添加邮件页眉说明&#xff0c;第一行显…

结构光双目视觉测距原理

结构光视觉技术是一种主动投影式的三维测量技术&#xff0c;通过使用投影仪和相机组成的系统来对物体进行三维测量 系统结构&#xff1a; 硬件系统&#xff1a; 常见编码方法&#xff1a; 结构光图案编码 常用的是格雷码和传统的二进制码相比&#xff0c;格雷码的编码数中任意…

c++静态成员函数为什么不能为虚函数?

知乎用户 three passions govern my life2 人赞同可以把静态成员函数看作是“命名空间受限的普通函数”&#xff0c;所以它不能有运行时多态发布于 2015-06-23 添加评论 感谢 分享收藏 • 没有帮助 • 举报 • 作者保留权利Elvis Wang C程序员转型Java中6 人赞同其实我觉得这个…

如何成为一个优秀的高级C++程序员

C这门语言从诞生到今天已经经历了将近30个年头。不可否认&#xff0c;它的学习难度都比其它 语言较高。而它的学习难度&#xff0c;主要来自于它的复杂性。现在C的使用范围比以前已经少了很多&#xff0c;java、C#、python等语言在很多方面已经可以代替 C。但是也有很多地方是其…

c++标准库 及 命名空间std

1、命名空间std   C标准中引入命名空间的概念&#xff0c;是为了解决不同模块或者函数库中相同标识符冲突的问题。有了命名空间的概念&#xff0c;标识符就被限制在特定的范围(函数)内&#xff0c;不会引起命名冲突。最典型的例子就是std命名空间&#xff0c;C标准库中所有标…

相机标定原理和opencv代码解析

1.单目标定 单应矩阵 设三维空间点的齐次坐标,对应的图像坐标为 他们满足一下关系&#xff1a; s为尺度因子&#xff0c;K为内参矩阵 R和T旋转平移矩阵统称为外参 假设我们提供K个棋盘图像&#xff0c;每个棋盘有N个角点&#xff0c;于是我们拥有2KN个约束方程。与此同时&am…

HUE 提交Schedule 时区问题

1.配置如下&#xff0c;每天定时 14:02 启动 2.运行后&#xff0c;任务状态提示&#xff0c;时间变成了06:02:00 3.修改HUE的时区配置 修改后 3.重启 4.然后执行发现&#xff0c;还是不起作用&#xff0c;后排查了一下oozie问题&#xff0c;发现hue的时区配置对oozie无法生效…

cuda的global memory介绍

CUDA Memory Model 对于程序员来说&#xff0c;memory可以分为下面两类&#xff1a; Programmable&#xff1a;我们可以灵活操作的部分。Non-programmable&#xff1a;不能操作&#xff0c;由一套自动机制来达到很好的性能。 在CPU的存储结构中&#xff0c;L1和L2 cache都是n…

Mybase到期 破解

1.找到mybase安装目录 C:\Users\Zsh\AppData\Local\wjjsoft\nyfedit6 2.打开nyfedit.ini 3. 内容中查找 App.UserLic.FirstUseOn 删除 4.保存打开mybase即可

Android中给按钮同时设置背景和圆角示例代码

前言 最近在做按钮的时候遇到在给按钮设置一张图片作为背景的同时还要自己定义圆角&#xff0c;最简单的做法就是直接切张圆角图作为按钮就可以了&#xff0c;但是如果不这样该怎么办呢&#xff0c;看代码&#xff1a; 下面来看效果图 一、先建一个圆角的shape文件&#xff1a;…

awk使用方法

awk是行处理器: 相比较屏幕处理的优点&#xff0c;在处理庞大文件时不会出现内存溢出或是处理缓慢的问题&#xff0c;通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理&#xff0c;然后输出 awk命令形式: awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’…

cude的__ldg使用

一般使用__ldg是更好的选择。通过constant缓存存储的数据必须相对较小而且必须获取同一个地址以便获取最佳性能&#xff0c;相反&#xff0c;只读缓存则可以存放较大的数据&#xff0c;且不必地址一致。 __global__ void transpose2(const real* A, real* B, const int N) {co…

cuda的shared momery

CUDA SHARED MEMORY 在global Memory部分&#xff0c;数据对齐和连续是很重要的话题&#xff0c;当使用L1的时候&#xff0c;对齐问题可以忽略&#xff0c;但是非连续的获取内存依然会降低性能。依赖于算法本质&#xff0c;某些情况下&#xff0c;非连续访问是不可避免的。使用…

图的表示方法和C++实现

图的表示最长用的两种方法是&#xff1a; 1&#xff09;、邻接矩阵表示法 2&#xff09;、邻接表表示 下面是两种构造图的方法 1&#xff09;邻接矩阵&#xff1a; [cpp] view plaincopy#include <iostream> #include <vector> using namespace std; //枚…