算法熟记-排序系列-堆排序

1. 简述

    假设待排序数组为 int array[], 数组长度为n。
    主要是利用堆的性质。对于升序排序,使用最大堆。
    首先,建堆,使用递归后根序遍历得方法,通过交换元素,保证根元素比孩子元素大。
    第1趟,堆顶元素array[0]与array[n-1]交换,保证array[n-1]的数值正确,根据array[0]新的数值更新堆。
    第2趟,堆顶元素array[0]与array[n-2]交换,保证array[n-2]的数值正确,根据array[0]新的数值更新堆。
    ···

    第n-1趟,堆顶元素array[0]与array[1]交换,保证array[1]的数值正确,根据array[0]新的数值更新堆。

2. 复杂度

    平均时间复杂度为O(N*logN),空间复杂度为O(1)。

3. 代码   

void make_heap(int array[], int n, int node) { // 自底向上,构建堆
  int left = 2 * node + 1;
  
int right = 2 * node + 2;
  
if(left > n-1return;
  
else if(right > n-1) { // 堆是完全的二叉树,所以此时不需要递归
    if(array[node] < array[left]) {
      swap(array[node], array[left]);
    }
  }
  
else {
    make_heap(array, n, left);
    make_heap(array, n, right);
    
if(array[node] < array[left] && array[right] <= array[left]) {
      swap(array[node], array[left]);
    }
    
else if(array[node] < array[right] && array[left] <= array[right]) {
      swap(array[node], array[right]);
    }
  }
}
void update_heap(int array[], int n, int node) { // 自顶向下,更新堆
  int left = 2 * n + 1;
  
int right = 2 * n + 2;
  
if(left > n-1return;
  
else if(right > n-1) {
    
if(array[node] < array[left]) 
      swap(array[node], array[left]);
  }
  
else {
    
if(array[node] < array[left] && array[right] <= array[left]) {
      swap(array[node], array[left]);
      update_heap(array, n, left);
    }
    
else if(array[node] < array[right] && array[left] <= array[right]) {
      swap(array[node], array[right]);
      update_heap(array, n, right);
    }
  }
}
void heap_sort(int array[], int n) {
  make_heap(array, n, 
0);
  
for(int i=n; i>=1; i--) {
    swap(array[i], array[
0]);
    update_heap(array, n, node);
  } 
}

    实际上,堆的构建和更新都可以使用非递归的方式实现,对于堆的构建,需要首先找到最后一个有孩子的节点array[k],然后从array[k]一直更新到array[0]即可,其中的k=n/2。k的求法如下:假设k存在,2*k+1=n或者2*k+2=n,对于第一种情况,k==n/2,对于第二种情况,k==n/2-1。对于堆的更新,就更简单了,只要从array[0]开始,选择一条通路,一直向下更新,直到没有孩子了为止。
   值得注意的是,对于下标从0开始的数组,k号节点的孩子节点分别是2*k+1和2*k+2。 而对于下标从1开始得数组,k号节点的孩子节点分别是2*k和2*k+1。
    堆排序属于选择排序,实际上就是利用最大堆这个数据结构,每次选择一个剩余元素中最大的元素,交换到合适的位置上去。

4. 参考资料

    维基百科-堆排序    http://en.wikipedia.org/wiki/Heapsort

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

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

相关文章

oracle入库的速度能到多少_多线程能提高Oracle的入库速度吗

多线程能提高Oracle的入库速度吗最近常常和同事们讨论“系统架构”&#xff0c;其中有不免提到如何使用“多线程”来改善系统性能。有些同事普遍有一种“认为”&#xff1a;他们认为“多线程”是改善系统性能的“灵丹妙药”&#xff0c;他们简单的认为&#xff0c;“多线程”导…

数据结构-- 线性表之链式存储

https://www.cnblogs.com/ZWOLF/p/10604252.html

那些年,我和发哥在恒大的日子

在广州上班那会&#xff0c;我们在恒大中心旁边的利通大厦上班&#xff0c;我和薛总每天一起上下班&#xff0c;那时候宿舍还有盼盼&#xff0c;有时候玩开心的时候&#xff0c;我就会跟他们说&#xff0c;等过了很多年后&#xff0c;我们要写一本说&#xff0c;书的名字就叫做…

十六进制转化为十进制

package lsh.element.numbersystem;import java.util.Scanner;/*** * desc 有意思的地方&#xff1a;两种思想得到的结果都是正确的&#xff0c;但是超出int类型最大之后&#xff0c;错误值却不同* * author * LSH* 2018年9月23日*/ public class HexToDecimalConver…

回来了

三年了 又回来了 未来去哪里转载于:https://blog.51cto.com/itcnjd/589429

KEIL高级调试——条件断点

在线调试程序时&#xff0c;打断点是非常有效的一种方式&#xff0c;配合单步调试&#xff0c;可以快速定位问题。但是有时候&#xff0c;手动打断点用起来不是那么方便。比如想要在一个循环的第N次停下来&#xff0c;如果手动打断点&#xff0c;那就要不停的点击单步运行&…

emailjava中怎么校验_Java使用注解实现参数统一校验功能

在项目开发中&#xff0c;当使用配置文件的时候&#xff0c;需要对一些配置参数进行合法校验&#xff0c;如果不存在则会抛出异常或者提醒用户重新修改配置文件后运行系统。 以前的做法就是读取到配置文件后&#xff0c;每个配置项挨个检查&#xff0c;写多个if判断是否存在问题…

原来保险丝熔断原理是这样的

如果电路中的保险丝熔断了&#xff0c;想亮起一个灯来指示&#xff0c;可以考虑用这个电路&#xff1a;这个电路的工作逻辑&#xff1a;当保险丝F1正常工作时&#xff0c;只亮起绿灯LED2。当保险丝F1熔断时&#xff0c;熄灭绿灯LED2&#xff0c;亮起红灯LED1&#xff0c;告诉人…

redhat6 使用raid5的系统安装

raid5安装步骤&#xff08;有三个磁盘&#xff0c;分别是sda/sdb/sdc&#xff09; 1.独立给/boot创建一个分区&#xff08;可以在创建software raid前后创建&#xff0c;但是不能加入raid software,例如&#xff1a;一个磁盘为sda&#xff0c;那我们把sda1作为/boot的独立分区&…

docker 定时重启脚本_使用 Go 添加启动脚本

简介实践困惑总结当前部分的代码简介虽然 Makefile 能很好的整合各种命令, 是一个非常方便的工具. 但启动脚本也是必不可少的, Makefile 更多用于开发阶段, 比如编译, 单元测试等流程.启动脚本的作用是控制程序的状态, 管理程序的启动, 停止, 查询运行状态等.实践直接上脚本了:…

SpringBoot在自定义类中调用service层等Spring其他层

解决方案&#xff1a; 1.上代码Component public class ServerHandler extends IoHandlerAdapter {Autowiredprotected HealthDataService healthDataService;private static ServerHandler serverHandler ;PostConstruct //通过PostConstruct实现初始化bean之前进行的操作pu…

为什么我的U盘空间变小了:图解 FAT 文件系统基础知识

作者 | 鱼鹰Osprey转自 | 鱼鹰谈单片机FAT 文件系统是什么&#xff0c;当你格式化 U 盘之后 U 盘发生了什么&#xff0c;为什么删除的文件还可以再恢复&#xff1f;买的 U 盘明明写着 16 G&#xff0c;实际却只有15 G&#xff0c;这里隐藏了什么事实&#xff1f;FAT 文件系统随…

持续集成(CI)- 各种工具的资料总结

为了实施CI&#xff0c;必须使用工作的支持&#xff0c;以使整个过程的自动化进行&#xff0c;以下把该过程涉及的各种工具汇集一下 必须的工具和功能 源代码控制系统 微软的工具: Microsoft Team Foundation Server (TFS) 或VSS 开源工具: 服务端&#xff1a; Subversion&…

如何用python制作动画的软件_大牛Python程序员制作3D动态可视化教程

Bar3D(3D 柱状图)name -> str图例名称x_axis -> strx 坐标轴数据。需为类目轴&#xff0c;也就是不能是数值。y_axis -> stry 坐标轴数据。需为类目轴&#xff0c;也就是不能是数值。data -> [list], 包含列表的列表数据项&#xff0c;数据中&#xff0c;每一行是一…

Python开课复习10

# 储备知识:# 函数的使用应该分为两个明确的阶段# 1. 定义阶段:只检测语法,不执行函数体代码def func(): print(from func)# 2. 调用阶段:会触发函数体代码的执行# func()#先定义后调用# 示范一# def foo():# print(from foo)# bar()# foo()# # 示范二:# def bar():…

如何DIY一款属于自己的HID键盘?

这是一个自定义游戏键盘&#xff0c;带有四个热插拔机械键和可自定义的RGB LED。它由STM32F103Cx微控制器供电&#xff0c;并通过Arduino IDE进行编程。文章末尾分享该项目资料。功能概述&#xff1a;快速STM32F103Cx微控制器可实现低输入延迟。USB全速&#xff0c;轮询速率为1…

给要学习.NET(c#语言)的新手一些学习方法

推荐两本书 第一本是《21天学通c#语言》 可能这本书的出版时间有点早&#xff0c;一些新的技术没涉及到&#xff0c;但是作为基础这本书是很不错的。 【原 书 名】 Sams Teach Yourself C# in 21 Days 【原出版社】 Sams 【作 者】&#xff08;美&#xff09;Bradley L.Jones…

arm9重启ssh服务_部署ssh使用rsa登录配置

什么是ssh?ssh专为远程登录会话和其他网络服务提供安全性的协议&#xff0c;利用ssh协议可以有效的防止远程管理过程中的信息泄露问题。使用ras公钥登录linux操作环境本地服务器&#xff1a;win10 远程服务器&#xff1a;centos 8 git环境生成rsa文件在windows机器上&#xff…

Android MVP模式简单易懂的介绍方式 (一)

Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式。看了很多文章&#xff0c;基本上都是长篇大论&#xff0c;一堆理论。但这里&#xff0c;我们不从理论出发&#xff0c…

什么?TTL信号也能高速稳定传输100m+?是的,你没有听错,量产电路推荐!

作者&#xff1a;周工&#xff0c;排版&#xff1a;晓宇微信公众号&#xff1a;芯片之家&#xff08;ID&#xff1a;chiphome-dy&#xff09;TTL传输100米&#xff0c;是不是很惊讶&#xff1f;早就看透了你的心思。传输100米&#xff0c;干嘛不用差分信号&#xff1f;就知道你…