数据结构---堆排序

news2024/11/18 4:33:53

堆排序

  • JAVA实现
  • 和快速排序区别

二叉堆的构建,删除,调整是实现堆排序的基础
之前博客写了二叉堆: 二叉堆

  1. 最大堆的堆顶是整个堆中的最大元素。
  2. 最小堆的堆顶是整个堆中的最小元素。

堆排序步骤:

  1. 把无序数组构建成二叉堆。(需要从小到大排序,则构建成最大堆;需要从大到小排序,则构建成最小堆。)
  2. 循环删除堆顶元素,替换到二叉堆的末尾,调整堆产生新的堆顶。

最后删除的元素依次组成了有序的数列。

第一步:删除一个最大堆的堆顶(并不是完全删除,而是跟末尾的节点交换位置)
第二步:再过自我调整,第2大的元素就会被交换上来,成为最大堆的新堆顶

在这里插入图片描述
先删除堆顶元素(跟末尾的节点交换位置)
在这里插入图片描述
再自我调整(第2大的元素就会被交换上来)
在这里插入图片描述
由于二叉堆的这个特性,每一次删除旧堆顶,调整后的新堆顶都是大小仅次于旧堆顶的节点。那么只要反复删除堆顶,反复调整二叉堆,所得到的集合就会成为一个有序集合:

删堆顶9,8变成新堆顶
在这里插入图片描述
删除节点8,节点7成为新堆顶。
在这里插入图片描述
在这里插入图片描述
。。。。循环往复
在这里插入图片描述
删除3,
在这里插入图片描述

原本的最大二叉堆已经变成了一个从小到大的有序集合。
二叉堆实际存储在数组中,数组中的元素排列如下
在这里插入图片描述

JAVA实现

package mysort.heapSort;

import java.util.Arrays;

//构建最大堆
public class heapSort {

    /**
     * “下沉”调整(删除元素)
     * @param array        待调整的堆
     * @param parentIndex  要“下沉”的父节点
     * @param length       堆的有效大小
     */
    public static void downAdjust(int[]array,int parentIndex,int length){
        // temp 保存父节点值,用于最后的赋值
        int temp = array[parentIndex];
        int childIndex = 2*parentIndex+1;
        while (childIndex<length){
            // 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子
            //找的是左右孩子里面最大的孩子
            if (childIndex+1<length&&array[childIndex+1]>array[childIndex]){
                childIndex++;
            }
            // 如果父节点大于任何一个孩子的值,则直接跳出
            //说明父节点比子节点大了,就没必要交换了(构建最大堆)
            if(temp>=array[childIndex]){
                break;
            }
            ///无须真正交换,单向赋值即可
            array[parentIndex] = array[childIndex];
            //再向下找,直到childIndex>=length,结束
            parentIndex = childIndex;
            childIndex = 2*childIndex+1;
        }
        //最后再把初始的父节点值赋值过去
        array[parentIndex]=temp;
    }

    /**
     * 构建最大堆
     * @param array 待调整的堆
     */
    public static void buildHeap(int[] array){
        // 从最后一个非叶子节点(array.length-2)/2)开始,依次做“下沉”调整
        for (int i = (array.length-2)/2;i>=0;i--){
            downAdjust(array,i,array.length);
        }
    }


    /**
     * 用最大堆排序(升序)
     * @param array  待调整的堆
     */
    public static void heapSort(int[]array){
        // 1. 把无序数组构建成最大堆
        buildHeap(array);
        System.out.println("构建成功,最大堆是:" + Arrays.toString(array));
        //执行堆排序(把堆顶元素删除,放到末尾)
        for (int i =array.length-1;i>0;i--){
            // 最后1个元素和第1个元素进行交换
            int temp = array[i];
            array[i] = array[0];
            array[0] = temp;
            //再把堆顶元素下沉,调整最大堆
            //这里,注意:i
            //随着i--.之前的最后的几位就保存排序好的数字了,就不动了
            downAdjust(array,0,i);
        }
    }
    public static void main(String[] args) {
        int[] arr = new int[]{1,3,2,6,5,7,8,9,10,0};
        heapSort(arr);
        System.out.println("堆排序之后的结果为: "+Arrays.toString(arr));
    }
}

在这里插入图片描述

最大堆排序(升序排序)

空间复杂度是O(1)
时间复杂度:

  1. 把无序数组构建成二叉堆,这一步的时间复杂度是O(n)。
  2. 循环删除堆顶元素,并将该元素移到集合尾部,调整堆产生新的堆顶。需要进行n-1次循环。每次循环调用一次downAdjust方法,所以第2步的计算规模是 (n-1)×logn ,时间复杂度为O(nlogn)。(二叉堆的节点“下沉”调整(downAdjust 方法)是堆排序算法的基础,时间复杂度是O(log n)。)
  3. 两个步骤是并列关系,所以整体的时间复杂度是O(nlogn)。

和快速排序区别

堆排序和快速排序的平均时间复杂度都是O(nlogn),并且都是不稳定排序。
至于不同点,快速排序的最坏时间复杂度是O(n2),而堆排序的最坏时间复杂度稳定在O(nlogn)。

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

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

相关文章

ArcGIS基础:等高线数据生成栅格DEM数据

以下操作为生成栅格DEM数据的方法。 一般方法是先创建TIN&#xff0c;然后在转为栅格DEM数据。 原始数据如下&#xff1a;为等高线数据&#xff0c;创建TIN数据需要用到等高线数据的【高程】字段。 声明&#xff1a;数据来源于网络。 工具位于【3D分析工具】下的【TIN】下…

BeanDefinition

1. 前言 Spring最重要的一个概念当属Bean了&#xff0c;我们写的Controller、Service、Dao凡是加了对应注解交给Spring管理的&#xff0c;都是Spring容器中的一个Bean。把我们自己写的类变成一个Bean交给Spring管理有很多的好处&#xff0c;比如我们不用自己去new对象了&#…

ssh+mysql实现的Java web企业人事人力资源管理系统源码+运行教程+参考论文+开题报告

今天给大家演示的是一款由sshmysql实现的Java web企业人事人力资源管理系统&#xff0c;其中struts版本是struts2&#xff0c;本系统功能非常完善&#xff0c;已经达到了可以商用的地步&#xff0c;基本全部实现了整个人力资源管理的所有功能&#xff0c;包括员工档案信息、部门…

jekins集成部署

jekins集成部署1.jekins简介2.Jenkins部署环境3. jekins安装4.配置jekins启动和停止脚本5.插件安装5.1.安装maven插件安装5.2 安装gitee插件5.3 安装Publish Over SSH插件5.4 安装 事件机制插件6.任务构建6.1 构建任务6.2 配置giteeApi令牌6.3 配置gitee源码地址6.4 在build中配…

3D激光里程计其二:NDT

3D激光里程计其二&#xff1a;NDT1. 经典NDT2. 计算方式2.1 2D场景求解:2.2 3D场景求解&#xff1a;3. 其他 NDTReference:深蓝学院-多传感器融合 1. 经典NDT NDT 核心思想&#xff1a;基于概率的匹配。目标是将点集 Y 匹配到固定的点集 X 中。这里的联合概率说的是将 X 划分成…

计算机毕业设计springboot+vue社区疫情防控系统

项目介绍 本系统运用最新的技术springboot框架,此框架是现在社会公司生产中所用的必需框架,非常实用,相比于以前的ssm框架,简单很多。前端框架运用vue框架,vue框架是最近几年非常流行的前端技术,适合很多开发语言。主要可以是系统的前端和后端进行解耦,分离,有利于开发者分别注…

设计模式——中介者模式

中介者模式一、基本思想二、应用场景三、结构图四、代码五、优缺点优点缺点一、基本思想 定义一个中介对象来封装一系列对象之间的交互&#xff0c;使原有对象之间的耦合松散&#xff0c;且可以独立地改变它们之间的交互。中介者模式又叫调停模式&#xff0c;它是迪米特法则的…

Proteus8仿真:51单片机LCD1602显示

51单片机LCD1602显示元器件原理图部分代码main.c工程文件元器件 元器件名称排阻RESPACK-851单片机AT89C51LCD1602LM016L按键BUTTON 原理图部分 LCD1602驱动: HD44780显示主要有8位操作8位两行显示&#xff0c;4位操作8位一行显示&#xff0c;8位操作8位一行显示。 LCD1602主要…

【Python】循环语句

目录 1.while 循环 2. for 循环 3. continue 4. break 1.while 循环 基本语法格式 while 条件&#xff1a; 循环体 条件为真&#xff0c;则执行循环体代码 条件为假&#xff0c;则结束循环 例1&#xff1a;打印 1 - 10 的整数 num 1 while num < 10:print(num)num 1 …

【AI with ML】第 10 章 :创建 ML 模型以预测序列

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

MySQL底层索引

目录 一、什么是索引&#xff1f; 二、MySQL索引结构分析【MySQL底层采用的是BTree】 1、为什么不使用二叉树&#xff1f; 2、为什么不使用红黑树&#xff1f; 3、为什么不使用Hash&#xff1f; 4、BTree与B-Tree的区别&#xff1f; 三、MySQL数据库的表结构、索引、数据 1、M…

基于Sharfetter-Gummel和改进的Sharfetter-Gummel计算对流扩散方程的通量(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

1. Arthas的命令

万恶淫为首&#xff0c;百善孝为先 Arthas命令 可以查看相应的文档: https://arthas.aliyun.com/doc/命令.html 如: https://arthas.aliyun.com/doc/grep.html https://arthas.aliyun.com/doc/cat.html 基础命令 help 查看命令帮助信息 cat 查看当前arthas 系统中的任意文件…

【算法】八月算法打卡

2022-08-01 低配版 promise class MyPromise {constructor(executor) {// 成功回调队列this._resolveQueue [];// 失败回调队列this._rejectQueue [];let resolve (val) > {while (this._resolveQueue.length) {const callback this._resolveQueue.shift();callback(v…

【iOS】对象,消息,运行期

文章目录对象&#xff0c;消息&#xff0c;运行期属性属性特质原子性方法名在对象内部尽量直接访问实例变量对象等同性特定类所具有的等同性判断等同性判定的执行深度容器中可变类的等同性以“类族模式”隐藏实现细节创建类族Cocoa里的类族在既有类中使用关联对象存放自定义数据…

原型,原型链,原型的继承

原型的作用? 1.节省内存空间 2.实现数据共享(继承) 什么是原型? 任何一个函数都有propotype属性,它本身是一个对象,我们称之为原型 构造函数,实例化对象与原型之间的关系? 1.任何一个函数都有prototype属性,它本身是一个对象,我们称之为原型 2.构造函数也是函数,也都…

C语言中头文件(.h)编写,头文件的包含<>和““很大不同

头文件书写技巧 1、头文件主要作用&#xff0c;提前声明函数&#xff0c;因为在c语言中必须先声明或定义才能使用 2、在使用到.c文件中需要把这个.h文件进行包含格式是#include <h文件>或#include "h文件名"&#xff0c;但**强烈建议用引号**&#xff0c;尖括…

【码极客精讲】do while语句

上次讲了while语句&#xff0c;这次讲一下do while语句。 do...while 循环是 while 循环的变体。在检查while()条件是否为真之前&#xff0c;该循环首先会执行一次do{}之内的语句&#xff0c;然后在while()内检查条件是否为真&#xff0c;如果条件为真的话&#xff0c;就会重复…

binder调用流程分析

binder是一个非常好的跨进程通信工具&#xff0c;Android对其进行了各种封装&#xff0c;虽然我们用起来简单&#xff0c;但是理解起来却比较困难。 1.自己设计一个跨进程通信机制 在理解binder之前呢&#xff0c;首先我们想一下&#xff0c;如果我们自己设计一个跨进程通信的…

关于树形dp问题的解决

文章目录解决套路案例展示一、二叉树的最大深度二、判断是不是平衡二叉树三、判断是不是二叉搜索树四、判断是否是满二叉树五、二叉树节点间的最大距离六、派对的最大快乐值解决套路 实际上就是设计一个递归函数&#xff0c;该递归函数一定要包含 basecase&#xff0c;即让函数…