堆排序详解

news2024/11/21 17:45:30

如有错误,感谢不吝赐教、交流

文章目录

  • 算法原理
    • 大根堆
      • 构建大根堆
    • 小根堆
  • Java实现完整代码
  • 总结

算法原理

堆是一个数组,可以被看成一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左向右填充。
这里我们为了是数组中节点具有以下性质:第i个节点的父节点为(i)/2,左孩子节点为2i, 右孩子节点为2i + 1,故对于长度为n个元素的堆,使用n+1长度的数组,第0号位置不存入堆元素值。

返回节点i的父节点:

public static int parent(int i) {
        return i >> 1;  // 使用移位运算比除法快
    }

返回左孩子节点

public static int left(int i) {
        return i << 1;
    }

返回右孩子节点

 public static int right(int i) {
        return (i << 1) + 1;
    }

构建如图所示:注意数组下标是从1开始,即0号位置没有使用
在这里插入图片描述

大根堆

除了根节点以外的所有节点,都要满足A[parent[i]] >= A[i],即对于一个节点,它的值大于所有孩子节点的值

构建大根堆

维持大根堆的性质:如果左右孩子的值大于自己,就交换,否则不变

public static void maxHeapify(int a[], int i, int heapSize) {
        int l = left(i);
        int r= right(i);

        int largest;
        if (l <= heapSize && a[l] > a[i]) {
            largest = l;
        } else {
            largest = i;
        }
        if (r <= heapSize && a[r] > a[largest]) {
            largest = r;
        }
        if (largest != i) {
            exchange(a, largest, i);
            maxHeapify(a, largest, heapSize);
        }

    }

交换方法:

private static void exchange(int[] a, int largest, int i) {
        int temp = a[i];
        a[i] = a[largest];
        a[largest] = temp;
    }

建立大根堆:

public static void buildMaxHeap(int a[]) {
        int length = a.length - 1;
        // 大于length / 2位置的节点都是叶子节点
        for (int i = length / 2; i >= 1; i--) {
            maxHeapify(a, i, length);
        }
    }

堆排序的主入口:

public static void heapSort(int a[]) {
        buildMaxHeap(a);

        for (int j = a.length - 1; j >= 2; j--) {
            exchange(a, 1, j);
            maxHeapify(a, 1, j - 1);
        }
    }

小根堆

除了根节点以外的所有节点,都要满足A[parent[i]] <= A[i],即对于一个节点,它的值小于所有孩子节点的值。
小根堆的使用方法与大根堆是一样的。

Java实现完整代码

java实现大根堆排序的完整代码:

public class HeapSort {
    // 返回节点i的父节点
    public static int parent(int i) {
        return i >> 1;
    }
    // 返回左孩子节点
    public static int left(int i) {
        return i << 1;
    }
    // 返回右孩子节点
    public static int right(int i) {
        return (i << 1) + 1;
    }

    public static void maxHeapify(int a[], int i, int heapSize) {
        int l = left(i);
        int r= right(i);

        int largest;
        if (l <= heapSize && a[l] > a[i]) {
            largest = l;
        } else {
            largest = i;
        }
        if (r <= heapSize && a[r] > a[largest]) {
            largest = r;
        }
        if (largest != i) {
            exchange(a, largest, i);
            maxHeapify(a, largest, heapSize);
        }

    }
    // 交换largest和i节点对应位置的值
    private static void exchange(int[] a, int largest, int i) {
        int temp = a[i];
        a[i] = a[largest];
        a[largest] = temp;
    }

    // 建立大根堆
    public static void buildMaxHeap(int a[]) {
        int length = a.length - 1;
        // 大于length / 2位置的节点都是叶子节点
        for (int i = length / 2; i >= 1; i--) {
            maxHeapify(a, i, length);
        }
    }

    // 堆排序主入口
    public static void heapSort(int a[]) {
        buildMaxHeap(a);

        for (int j = a.length - 1; j >= 2; j--) {
            exchange(a, 1, j);
            maxHeapify(a, 1, j - 1);
        }
    }

    public static void main(String[] args) {
        // 多申请一个是第0个位置不用,是的数组满足第i个位置对应的父节点为i/2,左孩子为2i,右孩子为2i + 1
        int arr [] = new int[]{0, 1, 5, 7, 3, 4, 10, 9, 8, 6};
        heapSort(arr);
        for (int a :
                arr) {
            System.out.print(a + " ");
        }
    }

}

总结

堆排序的时间复杂度是O(logn),任何时候都只需要常数个额外的元素空间存储临时数据。
适用于大量数据下需要取出前100最大,或者前100最小等一些场景。

ps:计划每日更新一篇博客,今日2023-04-24,日更第八天,昨日更新:
冒泡排序
选择排序
插入排序
归并排序

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

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

相关文章

Linux如何定时执行任务

目录 crontab 介绍 安装crontab 服务操作说明 操作案例 crontab 介绍 Linux crontab是采用定期执行程序的命令&#xff0c;当安装完成操作 系统后&#xff0c;默认便会启动此任务调度命令&#xff0c;crond命令每分钟都会定期检查是否要执行任务的工作&#xff0c;如果要执…

【链表】力扣206题:反转链表

【链表】力扣206题&#xff1a;反转链表 力扣206题&#xff1a;反转链表 建议在看题目之前先了解数组的具体知识点&#xff0c;可以看这里&#xff1a; 算法基础&#xff08;三&#xff09;&#xff1a;链表知识点及题型讲解。 其它题目&#xff1a; 【链表】力扣203题&#xf…

12 JS03——数据类型

目标&#xff1a; 1、数据类型简介 2、简单数据类型 3、获取变量数据类型 4、数据类型转换 5、拓展阅读 一、数据类型简介 1、为什么需要数据类型 在计算机中&#xff0c;不同的数据所需占用的存储空间是不同的&#xff0c;为了便于把数据分成所需内存大小不同的数据&#x…

GWO灰狼优化算法以及Matlab代码

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 GWO灰狼算法原理进化更新位置更新&#xff08;紧随3只头狼&#xff09; GWO灰狼算法流程图GWO优化算法matlab代码main函数适应度函数GWO主体代码测试结果F1~ F6测试…

ESP8266通过MQTT协议连接onenet云平台

中国移动onenet平台 文章目录 中国移动onenet平台前言一、onenet平台二、ESP82661.完整代码2.联网代码3.连云代码4.数据处理 总结 前言 最近在弄onenet平台&#xff0c;用arduino结合esp8266&#xff0c;就是不知道怎么回事&#xff0c;一直连不上wifi&#xff0c;然后就用esp…

基础知识回顾

1.数组 数组工具类 二维数组 1.1概念 数组&#xff0c;标志是[ ],用于存储多个相同类型数据的集合&#xff0c;获取数组中的元素通过脚标&#xff08;下标&#xff09;来获取&#xff0c;数组下标是从0开始的 1.2创建数组 创建数组的方式分为两种 动态初始化 int[] a ne…

〖ChatGPT实践指南 - 零基础扫盲篇②〗- 深度体验 ChatGPT

文章目录 ⭐ ChatGPT 最主要的对话功能⭐ ChatGPT 对话功能的演示&#x1f31f; 搞怪案例 ① - 询问如何做 "红烧肉"&#x1f31f; 演示案例 ② - 文本翻译[翻译源码]&#x1f31f; 演示案例 ③ - 代码问题&#x1f31f; 演示案例 ④ - 修复Bug&#x1f31f; 演示案例…

串口收发字符/字符串

分析过程&#xff1a; 框图&#xff1a; 通过以上框图分析可知&#xff0c;需要分析芯片手册 RCC / GPIO / UART 1.RCC章节&#xff1a;使能对应GPIOG/GPIOB/UART4控制器 2.GPIO章节&#xff1a;1)设置引脚为复用功能模式 2)设置复用功能为串口功能 3.UART章节&#xff1a;1…

Docker常用操作

1、单机&#xff08;非docker&#xff09;启动java程序&#xff1a;nohup java -jar springbootstudy.jar 2、启动docker&#xff1a;service docker start &#xff08;构建好以后&#xff0c;就不需要了&#xff1a;docker build -f Dockerfile -t springboot-jar .&#x…

确定因果随机森林的树木数量 the number of trees

前言 推断因果性和分析异质性是统计学家在处理混杂任务中的圣杯。传统且主流的方法有:倾向性评分、分层分享、比例风险模型等。新的方法也有很多,代表就是:因果随机森林。这种算法,浅看难度一般,深入探索发现坑还是很多的。这篇博客不对算法做深入探讨,仅仅是我在阅读文…

Hudi数据湖技术之快速体验

目录 1 编译 Hudi1.1 第一步、Maven 安装1.2 第二步、下载源码包1.3 第三步、添加Maven镜像1.4 第四步、执行编译命令1.5 第五步、Hudi CLI测试 2 环境准备2.1 安装HDFS2.2 安装Spark 3.x 3 spark-shell 使用3.1 启动spark-shell3.2 模拟数据3.3 插入数据3.4 查询数据3.5 表数据…

TVM: An Automated End-to-End Optimizing Compiler for Deep Learning

https://www.usenix.org/conference/osdi18/presentation/chen 文章目录 TVM: An Automated End-to-End Optimizing Compiler for Deep Learning引言1. 简介2. 总览3. 优化计算图4. 生成张量运算4.1 张量表达式和调度空间4.3 嵌套并行与协作4.3 张量化4.4 显式内存延迟隐藏 5 .…

2023年-测试工程师面试题(前期面试的题目)

背景&#xff1a;小型电商公司&#xff0c;薪资&#xff1a;8-11k&#xff0c;职位&#xff1a;测试工程师&#xff0c;学历&#xff1a;本科 打开微信小程序“casa品集”&#xff0c;找出该小程序存在哪些bug&#xff1f; 并列出「商品详情页」的测试用例A,B两张表&#xff0c…

[Golang] Go语言基础一知半解??这些你容易忽视的知识点(第一期)

&#x1f61a;一个不甘平凡的普通人&#xff0c;致力于为Golang社区和算法学习做出贡献&#xff0c;期待您的关注和认可&#xff0c;陪您一起学习打卡&#xff01;&#xff01;&#xff01;&#x1f618;&#x1f618;&#x1f618; &#x1f917;专栏&#xff1a;算法学习 &am…

液压控制系列之活塞位置测量(带原点标定功能)

液压轴位置控制详细内容请参看下面博客文章: 液压轴位置闭环控制(比例伺服阀应用)_RXXW_Dor的博客-CSDN博客液压阀的基础知识请参看下面的博客文章:PLC液压控制系列之比例流量阀结构分析_RXXW_Dor的博客-CSDN博客比例流量阀液压同步控制的PID闭环调节可以参看下面这篇博文三…

生命周期引入

实例&#xff1a;mouted&#xff1a;当vue完成模板解析并把真实的DOM元素放入页面后调用mounted 生命周期&#xff1a; 又名&#xff1a;生命周期回调函数、生命周期函数、生命周期钩子是什么&#xff1a;vue在关键时刻帮我们调用的一些特殊名称的函数生命周期函数的名字不可更…

CEF与Qt 结合注意事项

默认情况下&#xff0c;CEF 是/MT&#xff0c;而Qt是/MD 那么&#xff0c;如果你没有去在意MT、MD选项&#xff0c;那么极大可能性&#xff0c;会遇到程序崩溃的问题&#xff0c;并且表象会误导你查明原因的方向。并且&#xff0c;更换多个IDE也无法查明原因。 例子 当加载网…

【Linux】Linux开发工具

Linux开发工具 前言Linux编辑器 --- vimvim长啥样vim的基本概念vim的配置 Linux编译器 --- gcc/g编译和链接预处理编译汇编链接 细&#x1f512;链接静态库和动态库 Linux调试器 --- gdbLinux项目自动化构建工具 --- make/Makefile依赖关系和依赖方法 上方工具的简单示例 前言 …

MyBatis(二)—— 进阶

一、详解配置文件 1.1 核心配置文件 官方建议命名为mybatis-config.xml&#xff0c;核心配置文件里可以进行如下的配置&#xff1a; <environments> 和 <environment> mybatis可以配置多套环境&#xff08;开发一套、测试一套、、、&#xff09;&#xff0c; 在…

c实例练习笔记(拓展)

本博文参考题目的地址看右边----》C技能树 我跟你说&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;c语言有bool类型&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;你是不是百度跟你说没有只有c才有&#xff1f; 是有的&#xff01;&#xf…