【数据结构与算法】十大经典排序算法-堆排序

🌟个人博客:www.hellocode.top
🏰Java知识导航:Java-Navigate
🔥CSDN:HelloCode.
🌞知乎:HelloCode
🌴掘金:HelloCode
⚡如有问题,欢迎指正,一起学习~~


堆排序是一种高效的排序算法,基于堆数据结构实现。堆是一种特殊的树状结构,具有以下特点:父节点的值大于等于(或小于等于)其子节点的值。堆排序利用堆的性质,将数组看作一个完全二叉树,通过构建最大堆(或最小堆),实现对数组的排序。

基本思想

这里采用五分钟学算法大佬的图解,十分清晰

  1. 构建初始堆:将待排序数组视为一个完全二叉树,从最后一个非叶子节点开始,逐步将树调整为大顶堆(或小顶堆)。
  2. 排序过程:将堆顶元素与最后一个叶子节点交换,然后将堆大小减一,继续调整堆结构,使其重新成为大顶堆(或小顶堆)。
  3. 重复步骤 2,直到堆大小为 1,排序完成。

需要掌握的部分知识:

  • 完全二叉树:指除了最后一层外,其他层的节点都被完全填满,最后一层的节点都靠左排列,并且不存在不规则的空缺。这意味着从根节点到倒数第二层都是满的,最后一层从左到右有可能存在空缺,但不能跳过空缺。
  • 堆:堆是一种基于完全二叉树的数据结构,可分为大顶堆和小顶堆。在大顶堆中,父节点的值大于等于其子节点的值;在小顶堆中,父节点的值小于等于其子节点的值。堆的性质使其适合用来进行排序和实现优先队列等数据结构。
  • 堆的构建和调整:在堆排序中,我们主要关注构建初始堆和调整堆的过程。构建初始堆的目标是将一个无序数组调整为一个最大堆或最小堆。调整堆的目标是保持堆的性质,确保父节点的值大于等于(或小于等于)子节点的值。
  • 完全二叉树中相关计算:对于任意节点来说,左子节点索引计算公式为2*i + 1,右子节点为:2*i + 2,最后一个非叶子节点计算公式为n/2 - 1(n为节点总数,i为当前节点索引)

这里的难点就是对应的概念和计算,拿到待排序数组后,首先需要将其构建为大顶堆(或小顶堆),然后需要进行相应的节点交换,并继续调整结构使其保持大顶堆(或小顶堆)特性,代码层面还需要配合动画多多理解

代码实现

相比之前的几种排序,堆排序就相对复杂一些,需要用到递归的思想。遇到递归,还是要考虑递归的出口,避免无休止的递归,这里使用递归就是不断调整来维持堆结构,自上而下递归,那么递归的出口就是到叶子节点(不能超出数组范围)。

主要分为三个方法:heapSort(对外提供的堆排序方法)、buildMaxHeap(构建初始堆结构方法)、heapify(真正调整堆结构、维持堆规则的方法)

package top.hellocode;import java.util.Arrays;/*** @author HelloCode* @blog https://www.hellocode.top* @date 2023年08月13日 20:01*/
public class HeapSort {public static void main(String[] args) {int[] arr = {19, 23, 13, 7, 84, 66, 98, 78, 54, 32, 23, 77, 88, 17};System.out.println("排序前:" + Arrays.toString(arr));heapSort(arr);System.out.println("排序后:" + Arrays.toString(arr));}public static void heapSort(int[] arr) {// 构建初始堆结构(默认大顶堆,实现升序排序)buildMaxHeap(arr, arr.length);// 开始排序// 从堆顶取出元素,并和最后一个元素进行交换,并不断调整维持堆结构for (int i = arr.length - 1; i > 0; i--) {int temp = arr[i];arr[i] = arr[0];arr[0] = temp;heapify(arr, 0, i);}}// 构建初始最大堆private static void buildMaxHeap(int[] arr, int length) {// 构建大顶堆,从最后一个非叶子节点开始((length - 1) / 2)for (int i = length / 2 - 1; i >= 0; i--) {heapify(arr, i, length);}}/*** 调整堆结构,使其成为最大堆* int[] arr:待调整数组* int index:子树根节点(从哪里开始向下调整)* int length:数组长度,主要用来判断子树递归是否到达了叶子节点(超出数组长度)*/private static void heapify(int[] arr, int index, int length) {// 默认假设当前子树根节点为最大值,寻找左右子节点是否有更大值int max = index;int left = 2 * index + 1;int right = 2 * index + 2;// 递归终止条件(出口)if (left >= length || right >= length) {return;}// 开始比较左右子节点if (arr[left] > arr[max]) {max = left;}if (arr[right] > arr[max]) {max = right;}// 如果最大值发生了变化,则进行交换// 只要是有交换发生,就需要对其子树继续进行递归调整if (max != index) {int temp = arr[index];arr[index] = arr[max];arr[max] = temp;// 继续对其子树递归调整heapify(arr, max, length);}}
}

测试:

排序前:[19, 23, 13, 7, 84, 66, 98, 78, 54, 32, 23, 77, 88, 17]
排序后:[7, 13, 17, 19, 23, 23, 32, 54, 66, 77, 78, 84, 88, 98]

优化

堆排序的核心是构建堆和调整堆,可以通过一些优化来提升性能。

  • 在构建堆的时候,有自顶向上和自底向下两种,不同的场景使用不同的方法性能也有不同,这里可以去了解了解,对对应的场景进行优化。

总结

优点

  1. 高效性:堆排序的时间复杂度为 O(n log n),在大规模数据下表现优异。
  2. 不占用额外空间:堆排序是原地排序算法,不需要额外的存储空间。

缺点

  1. 不稳定性:堆排序是不稳定的排序算法,相等元素的相对顺序在排序后可能发生变化。

复杂度

  • 时间复杂度
    • 平均时间复杂度:O(n log n)
    • 最好情况时间复杂度:O(n log n)
    • 最坏情况时间复杂度:O(n log n)
  • 空间复杂度:原地排序,空间复杂度为 O(1)。

使用场景

堆排序适用于大规模数据的排序,尤其在需要稳定排序时(如堆顶元素是最大值时)。虽然实现相对复杂,但其高效性使其成为处理大量数据的有力工具。在实际应用中,堆排序在需要高性能排序时可能是一个不错的选择。

当使用堆排序时,应特别注意其时间和空间复杂度的说明是基于固定的数据集。在实际情况中,堆排序的性能可能因为一些特定因素而有所不同,因此在特定情况下堆排序可能表现更好。

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

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

相关文章

用库造一个list的轮子 【C++】

文章目录 list的模拟实现默认成员函数构造函数拷贝构造函数赋值运算符重载析构函数 迭代器迭代器为什么要存在?const_iteratorbegin和end inserterasepush_back && pop_backpush_front &&pop_frontswap 完整代码 list的模拟实现 默认成员函数 构造…

HCIP BGP小综合

BGP小综合 AS配置AS1AS2 中的小自治系统64512AS2 中的小自治系统64513AS3 测试 首先该实验分成三个AS,AS2里面有联邦,所以配置顺序 要先将IBGP通,然后配置AS1,AS3和联邦 AS配置 AS1 R1 # bgp 1router-id 1.1.1.1peer 12.1.1.2 as-number …

二十二、责任链模式

目录 1、使用demo演示责任链模式2、传统方案解决oa系统审批3、传统方案解决oa系统审批存在的问题4、职责链模式基本介绍5、职责链模式原理类图6、职责链模式解决oa系统采购审批7、职责链模式的注意事项和细节8、职责链模式的实际使用场景举例 1、使用demo演示责任链模式 学校o…

数据库相关面试题

巩固基础,砥砺前行 。 只有不断重复,才能做到超越自己。 能坚持把简单的事情做到极致,也是不容易的。 mysql怎么优化 : MySQL的优化可以从以下几个方面入手: 数据库设计优化:合理设计表结构,选择合适的数…

GitHub 如何部署写好的H5静态页面

感谢粉皮zu的私信,又有素材写笔记了。(●’◡’●) 刚好记录一下我示例代码的GitHub部署配置,以便于后期追加仓库。 效果 环境 gitwin 步骤 第一步 新建仓库 第二步 拉取代码 将仓库clone到本地 git clone 地址第三步 部署文件 新建.github\workflo…

vue-pc端elementui-统一修改问题-Dialog 对话框点击空白关闭问题-element-所有组件层级问题

前言 实际开发我们经常发现dialog弹出框默认点击遮罩层空白地方就会关闭-有属性可以关闭 但是经常会图方便-或者已经写完了,不想一个个写,可以在main.js进行统一关闭 当我们在页面进行复杂设计和层级关闭改变,会发现右上角的退出登录弹出款…

现代无人机技术

目录 1.发展 2.应用领域 3.对战争的影响 4.给人类带来的福利 5.给人类带来的坏处 1.发展 无人机的发展可以分为以下几个关键步骤: 1. 早期试验和研究:20世纪初,飞行器的概念开始出现,并进行了一些早期的试飞和实验。这些尝试包…

LeetCode150道面试经典题-- 有效的字母异位词(简单)

1.题目 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 2.示例 s"adasd" t"daads" 返回true s"addad" t &q…

常见设计模式

概念 设计模式是怎么解决问题的一种方案 常见的设计模式 单例模式 概念:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 应用:项目封装个websocket用于大屏,redux,vuex都应用了单例模式的思想&#xff1b…

文献阅读:AnnoLLM: Making Large Language Models to Be Better Crowdsourced Annotators

文献阅读:AnnoLLM: Making Large Language Models to Be Better Crowdsourced Annotators 1. 文章简介2. 方法介绍3. 实验考察 1. 实验结果2. 消解实验3. Consistency & Stability 4. 结论 & 思考 文献链接:https://arxiv.org/abs/2303.16854 …

Golang设计模式

Golang设计模式 Golang设计模式简介Golang工厂设计模式Golang单例设计模式Golang抽象工厂设计模式Golang建造者模式 (Builder Pattern)Golang 原型模式(Prototype Pattern)Golang适配器模式Golang 桥接模式(Bridge Pattern)Golang装饰器模式(Decorator …

j东h5st参数多局部ob加密(js_security_v3_0.1.4.js)加密分析

j东h5st参数多局部多次ob加密(js_security_v3_0.1.4.js) 大家好呀,我是你们的好兄弟,【星云horseAK】,今天的主题真的是千呼万唤始出来,某东东的h5st参数,这个加密的js文件使用了obfuscator进行…

《Java-SE-第三十六章》之枚举

前言 在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!” 博客主页:KC老衲爱尼姑的博客主页 博主的github,平常所写代码皆在于此 共勉:talk is cheap, show me the code 作者是爪哇岛的新手,水平很有限&…

Linux 日志管理

Linux 日志管理 一.Linux 下的日志服务简介 1.1 CentOS5 之前的版本 centos5 之前的版本使用系统和内核日志分离的格式记录日志 syslogd:该服务专门用于记录系统日志(system application logs) klogd: 该服务专门用于记录内核日志(linux kernel logs) centos5 之前事件的记录格…

Redis_Geospatial(基于位置信息的应用)

12.Geospatial 12.1 简介 基于位置信息服务(Location-Based Service,LBS)的应用。Redis3.2版本后增加了对GEO类型的支持。主要来维护元素的经纬度。redis基于这种类型,提供了经纬度设置、查询、范围查询、距离查询、经纬度hash等一些相关操作 12.2 GEO底层结构 …

war和war exploded

war和war exploded的区别 war模式&#xff1a;将WEB工程以包的形式上传到服务器 &#xff1b; war exploded模式&#xff1a;将WEB工程以当前文件夹的位置关系上传到服务器&#xff1b;>> war包是自己打包生成的&#xff0c;如pom文件中<packaging>war</packag…

使用 Visual Studio Code 调试 CMake 脚本

之前被引入到 Visual Studio 中的 CMake 调试器&#xff0c;现已在 Visual Studio Code 中可用。 也就是说&#xff0c;现在你可以通过在 VS Code 中安装 CMake 工具扩展&#xff0c;来调试你的 CMakeLists.txt 脚本了。是不是很棒? 背景知识 Visual C 开发团队和 CMake 的维…

Flutter源码分析笔记:Widget类源码分析

Flutter源码分析笔记 Widget类源码分析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132259681 【介绍】&#x…

TestNG和Junit5测试框架梳理

一、testNG 1. testNG优势 注解驱动&#xff1a; TestNG 使用注解来标识测试方法、测试类和配置方法&#xff0c;使得测试更具可读性。 并行执行&#xff1a; TestNG 支持多线程并行执行测试&#xff0c;可以加速测试套件的执行。 丰富的配置&#xff1a; 可以通过 XML 配置文…