数据结构与算法之堆排序

news2024/11/19 4:19:34

目录

  • 堆排序概述
  • 代码实现
  • 时间复杂度

堆排序概述

堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

在这里插入图片描述同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
在这里插入图片描述该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

  • 大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

  • 小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)

1)假设给定无序序列结构如下
在这里插入图片描述
2)此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整
在这里插入图片描述
3)找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换
在这里插入图片描述4)这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。
在这里插入图片描述此时,我们就将一个无需序列构造成了一个大顶堆

步骤二 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换

1)将堆顶元素9和末尾元素4进行交换,9就不用继续排序了
在这里插入图片描述
2)重新调整结构,使其继续构建大顶堆(9除外)
在这里插入图片描述
3)再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.
在这里插入图片描述
步骤三 后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序
在这里插入图片描述

排序思路

  • 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

  • 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

  • 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序

动图展示

在这里插入图片描述

代码实现

import java.util.Arrays;

public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {4, 6, 8, 5, 9};
        heapSort(arr);
//        [4, 6, 8, 5, 9]
//        [4, 9, 8, 5, 6]
//        [4, 9, 8, 5, 6]
//        [9, 6, 8, 5, 4]
//        [9, 6, 8, 5, 4]
//        [9, 6, 8, 5, 4]
//        [8, 6, 4, 5, 9]
//        [8, 6, 4, 5, 9]
//        [6, 5, 4, 8, 9]
//        [6, 5, 4, 8, 9]
//        [5, 4, 6, 8, 9]
//        [5, 4, 6, 8, 9]
//        [4, 5, 6, 8, 9]
    }

    //堆排序
    public static void heapSort(int[] arr) {
        //开始位置是最后一个非叶子节点(最后一个节点的父节点)
        int start = (arr.length - 1) / 2;
        //循环调整为大顶堆
        for (int i = start; i >= 0; i--) {
            maxHeap(arr, arr.length, i);
        }
        //先把数组中第0个和堆中最后一个交换位置
        for (int i = arr.length - 1; i > 0; i--) {
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            //再把前面的处理为大顶堆
            maxHeap(arr, i, 0);
        }
    }

    //数组转大顶堆,size:调整多少(从最后一个向前减),index:调整哪一个(最后一个非叶子节点)
    public static void maxHeap(int[] arr, int size, int index) {
        //左子节点
        int leftNode = 2 * index + 1;
        //右子节点
        int rightNode = 2 * index + 2;
        //先设当前为最大节点
        int max = index;
        //和两个子节点分别对比,找出最大的节点
        if (leftNode < size && arr[leftNode] > arr[max]) {
            max = leftNode;
        }
        if (rightNode < size && arr[rightNode] > arr[max]) {
            max = rightNode;
        }

        //交换位置
        if (max != index) {
            int temp = arr[index];
            arr[index] = arr[max];
            arr[max] = temp;
            //交换位置后,可能会破坏之前排好的堆,所以之间排好的堆需要重新调整
            maxHeap(arr, size, max);
        }
        //打印每次排序后的结果
        System.out.println(Arrays.toString(arr));
    }
}

时间复杂度

  • 最优时间复杂度:o(nlogn)
  • 最坏时间复杂度:o(nlogn)
  • 稳定性:不稳定

它的运行时间主要是消耗在初始构建堆和在重建堆时的反复筛选上。

在构建堆的过程中,因为我们是完全二叉树从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和若有必要的互换,对于每个非终端结点来说,其实最多进行两次比较和互换操作,因此整个构建堆的时间复杂度为O(n)。

在正式排序时,第i次取堆顶记录重建堆需要用O(logi)的时间(完全二叉树的某个结点到根结点的距离为log2i+1),并且需要取n-1次堆顶记录,因此,重建堆的时间复杂度为O(nlogn)

所以总体来说,堆排序的时间复杂度为O(nlogn)。由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为O(nlogn)。这在性能上显然要远远好过于冒泡、简单选择、直接插入的O(n2)的时间复杂度了。

空间复杂度上,它只有一个用来交换的暂存单元,也非常的不错。不过由于记录的比较与交换是跳跃式进行,因此堆排序是一种不稳定的排序方法。

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

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

相关文章

LINE、SDNE和struc2vec图嵌入算法学习笔记

引言 在cs224w课程中&#xff0c;我先后总结了deepwalk、node2vec&#xff0c;这两种算是最经典也是最主流的做法&#xff0c;而在 图节点嵌入相关算法学习笔记 中&#xff0c;从头至尾&#xff0c;将一些经典算法用wiki的数据集复现了一下&#xff0c;所以本篇博文&#xff0…

2023版会声会影电脑配置要求及功能介绍

可能大家已经看到网络上关于会声会影2023新版的一些消息&#xff0c;今天coco玛奇朵在这里分享2023新版公布信息。会声会影2023中文版功能非常强大的视频编辑软件&#xff0c;非常专业的使用效果&#xff0c;会声会影2023可以针对剪辑电影进行使用&#xff0c;非常强大的色彩校…

借助CatGPT让turtlesim小乌龟画曲线

注意这里是CatGPT&#xff0c;不等同OpenAI的ChatGPT&#xff0c;但是用起来十分方便&#xff0c;效果也还行。详细说明ROS机器人turtlesim绘制曲线需要注意哪些ROS机器人turtlesim绘制曲线需要注意以下几点&#xff1a;绘制曲线前需要设置好turtlesim的初始位置和方向&#xf…

【matplotlib】条形图及垂线显示小技巧 |一些有用参考帖子收集

最近在画图。一方面看论文看思路&#xff0c;一方面用数据跑图出论文雏形。 有些帖子写得很好&#xff0c;不记录的话下次还想看就只能随缘了。 帖子 博客&#xff1a;nxf_rabbit75 matplotlib技巧—9.共享坐标轴、创建多个subplot、调整横坐标、放置文本框、latext文字、平移…

组播详解及示例代码

写在前面 由于公司业务需要用到组播实现&#xff0c;这里就记录下学习过程。在学习组播之前&#xff0c;我们先来看看另外两种数据包传输方式&#xff1a;单播和广播。 单播&#xff1a;简单来说就是数据一对一发送&#xff0c;如果需要给多个主机发送数据时&#xff0c;就需…

Unity入门精要02---纹理

纹理和材质不可分割 本节知识结构 实践&#xff1a;简单贴一张纹理到模型上 首先在属性处添加相关属性 Properties {_Color ("Color Tint", Color) (1, 1, 1, 1)_MainTex ("Main Tex", 2D) "white" {}//加入纹理_Specular ("Specular&q…

虚拟机VirtualBox下载与安装+虚拟机配置

1、虚拟机VirtualBox下载与安装官网地址&#xff1a;Oracle VM VirtualBox进入官网&#xff0c;点击左侧Dwonlaods点击Windows hosts&#xff0c;开始下载3.打开文件.出现报错&#xff1a;Oracle VM VirtualBox 7.0.4 needs the Microsoft Visual C 2019 Redistributable Packa…

转义字符\033(设置终端的字体显示效果)

以下内容源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 参考博客 命令行特殊显示效果\033和发声音\007_华硕他哥的博客-CSDN博客 \033格式:指定输出格式_51CTO博客_wkt格式 一、\033的说明 在关于ASCII字符的那些事儿中提到&#xff0c;ASCII字符可以使用前面…

2023年天津医科大学临床医学院专升本专业课考试通知

天津医科大学到临床医学院2023年高职升本科专业课考试通知一、考试时间、地点 天津医科大学临床医学院2023年高职升本科考试定于2023年3月25日举行&#xff0c;考试地点为天津市滨海新区大港学苑路167号天津医科大学临床医学院教学楼。 二、准考证打印开放时间 本次考试打印准考…

3.4笔试总结

感觉题目好难没有做过这种类型的填空题真的是给应届实习生做的题吗第一大题 填空题一开始题目放在pdf里,我都没看清题目想干嘛其实题目看起来复杂.如果仔细读题意还是能做出几个空,无奈我太过紧张浪费了好几分钟空档时间public class Main { public static boolean isRegularMa…

内核角度谈谈Linux进程和线程

目录前言内核对进程和线程的表示创建进程的过程创建线程的过程创建进程和线程的异同揭秘 do_fork 系统调用结论前言 昨天面试的时候&#xff0c;面试官问我了个平平淡淡的问题–>“聊聊Linux中进程和线程”; 相比大家不管是在考试还是面试中或多或少都遇到过这个问题&…

python高德地图+58租房网站平台源码

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;python地图 免费获取完整源码源文件说明文档配置教程等 在PyCharm中运行《高德地图58租房》即可进入如图1所示的高德地图网页。 具体的操作步骤如下&#xff1a; &#xff08;1&#xff09;打开地图网页后&#xff0c;在编…

xgboost:防止过拟合的方法收缩和特征列、采样

xgboost除了第2.1节中提到的正则化目标之外&#xff0c;还使用了另外两种技术来进一步防止过拟合1。 目录shrinkage[^1]Column Subsampling[^2]shrinkage2 第一种技术是由弗里德曼提出的收缩。在树提升的每一步之后&#xff0c;收缩率以η因子的比例缩放新添加的权重。与随机优…

Scrapy框架(高效爬虫)

文章目录一、环境配置二、创建项目三、scrapy数据解析四、基于终端指令的持久化存储1、基于终端指令2、基于管道3、数据同时保存至本地及数据库4、基于spider爬取某网站各页面数据5、爬取本页和详情页信息&#xff08;请求传参&#xff09;6、图片数据爬取ImagesPipeline五、中…

IP欺骗种类有哪些?

每台计算机都有一个IP地址&#xff0c;发送的任何数据都被分成许多块&#xff08;“数据包”&#xff09;&#xff0c;每个数据包单独传输&#xff0c;当这些数据包到达链的末端时&#xff0c;就会重新组装并作为一个整体呈现。此外&#xff0c;每个数据包还有其可识别信息&…

4、High-Resolution Image Synthesis with Latent Diffusion Models

简介github地址diffusion model明显的缺点是耗费大量的时间、计算资源&#xff0c;为此&#xff0c;论文将其应用于强大的预训练自编码器的潜在空间 &#xff0c;这是首次允许在复杂性降低和细节保存之间达到一个近乎最佳的点&#xff0c;极大地提高了视觉保真度。通过在模型架…

操作系统复习题

什么是线程&#xff1f; 线程&#xff08;Thread&#xff09;&#xff1a;轻量级进程&#xff0c;是操作系统进行调度的最小单位。一个线程是一个任务&#xff08;一个程序段&#xff09;的一次执行过程。线程不占有内存空间&#xff0c;它包括在进程的内存空间中。在同一个进程…

自然语言处理历史最全预训练模型(部署)汇集分享

什么是预训练模型&#xff1f;预练模型是其他人为解决类似问题而创建的且已经训练好的模型。代替从头开始建立模型来解决类似的问题&#xff0c;我们可以使用在其他问题上训练过的模型作为起点。预训练的模型在相似的应用程序中可能不是100&#xff05;准确的。本文整理了自然语…

踩坑:maven打包失败的解决方式总结

Maven打包失败原因总结如下&#xff1a; 失败原因1&#xff1a;无法使用spring-boot-maven-plugin插件 使用spring-boot-maven-plugin插件可以创建一个可执行的JAR应用程序&#xff0c;前提是应用程序的parent为spring-boot-starter-parent。 需要添加parent的包spring-boot…

QML组件

一个QML文件定义了一个独立的、顶级的QML组件。 一个QML组件就是一个模板&#xff0c;被QML运行环境解释来创建一个带有一些预定义行为的对象。 一个独立的QML组件可以运行多次来禅城多个对象&#xff0c;每个对象都可以称为该组件的实例。 例子&#xff1a; 在项目中添加一…