宝藏速成秘籍(7)堆排序法

news2024/10/5 15:22:42

一、前言

1.1、概念

       堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法 。堆是一个近似 完全二叉树 的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

 1.2、排序步骤  

  1. 构建最大堆(或最小堆):将待排序的数组构建为一个最大堆(或最小堆)。这可以通过从数组末尾开始,依次将每个节点调整到合适的位置来实现。调整的方法是将当前节点与其父节点比较,如果当前节点大于(或小于)父节点,则交换它们的位置,并重复这个过程直到当前节点符合最大堆(或最小堆)的性质。

  2. 交换堆顶和末尾元素:将最大堆(或最小堆)的堆顶元素与数组的最后一个元素交换位置。

  3. 破坏堆性质:将数组末尾的元素从堆中移除,即将数组的长度减一,并且将堆的根节点进行一次调整,使得剩余元素仍然满足最大堆(或最小堆)的性质。

  4. 重复步骤2和步骤3,直到堆的大小为1,即只剩下一个元素。

  5. 排序完成:最后得到的数组就是一个有序序列。

二、方法分析

       堆排序是一种基于堆数据结构的比较排序算法。堆是一种完全二叉树,分为最大堆和最小堆。在最大堆中,每个节点的值都大于或等于其子节点的值;在最小堆中,每个节点的值都小于或等于其子节点的值。堆排序通常使用最大堆进行升序排序。堆排序分为两个主要步骤:构建堆和排序。

三、举例说明 

对数组 `[4, 10, 3, 5, 1]` 进行堆排序

#### 步骤 1:构建最大堆

将数组视为一个完全二叉树,然后从最后一个非叶子节点开始,向前调整每个节点,使其符合最大堆的性质。

1. 初始数组: `[4, 10, 3, 5, 1]`
   - 二叉树表示:  

         4
        / \
       10  3
      /  \
     5    1

2. 从最后一个非叶子节点开始调整(节点 `10`,索引 `1`)。
   - 节点 `10` 已经大于它的子节点,所以不需要调整。

3. 调整节点 `4`(索引 `0`)。
   - 节点 `4` 的子节点为 `10` 和 `3`。由于 `10` 最大,将 `4` 和 `10` 交换。
   - 调整后数组: `[10, 4, 3, 5, 1]`
   - 二叉树表示:

         10
        / \
       4   3
      / \
     5   1

- 继续调整节点 `4`。它的子节点为 `5` 和 `1`,将 `4` 和 `5` 交换。
   - 调整后数组: `[10, 5, 3, 4, 1]`
   - 二叉树表示:
    

         10
        / \
       5   3
      / \
     4   1

现在,我们已经构建了一个最大堆。

#### 步骤 2:排序

将堆顶元素(最大值)与堆的最后一个元素交换,然后将剩余元素重新调整为最大堆,重复该过程直到所有元素有序。

1. 交换 `10` 和 `1`,并调整剩余部分为最大堆。
   - 调整后数组: `[1, 5, 3, 4, 10]`
   - 重新调整:

         1
        / \
       5   3
      /
     4

 - 节点 `1` 的子节点为 `5` 和 `3`,将 `1` 和 `5` 交换。
   - 调整后数组: `[5, 1, 3, 4, 10]`
   - 继续调整节点 `1`,将 `1` 和 `4` 交换。
   - 调整后数组: `[5, 4, 3, 1, 10]`
   - 二叉树表示:

         5
        / \
       4   3
      /
     1

2. 交换 `5` 和 `1`,并调整剩余部分为最大堆。
   - 调整后数组: `[1, 4, 3, 5, 10]`
   - 重新调整:

         1
        / \
       4   3

   - 节点 `1` 的子节点为 `4` 和 `3`,将 `1` 和 `4` 交换。
   - 调整后数组: `[4, 1, 3, 5, 10]`
   - 二叉树表示:

         4
        / \
       1   3

3. 交换 `4` 和 `3`,并调整剩余部分为最大堆。
   - 调整后数组: `[3, 1, 4, 5, 10]`
   - 重新调整:

         3
        / 
       1

  - 节点 `3` 的子节点为 `1`,不需要调整。

4. 交换 `3` 和 `1`。
   - 调整后数组: `[1, 3, 4, 5, 10]`
   - 重新调整:没有需要调整的部分。

最终,数组变为有序的 `[1, 3, 4, 5, 10]`。

通过上述步骤,堆排序成功地对数组进行了升序排列。

四、编码实现 

 下面是用Java实现的堆排序算法:

public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {4, 10, 3, 5, 1};
        heapSort(arr);
        System.out.println("排序后的数组:");
        for (int num : arr) {
            System.out.print(num + " ");
        }
    }

    public static void heapSort(int[] arr) {
        // 构建大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);
        }
        // 调整堆结构+交换堆顶元素与末尾元素
        for (int j = arr.length - 1; j > 0; j--) {
            swap(arr, 0, j);
            adjustHeap(arr, 0, j);
        }
    }

    public static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i]; // 先取出当前元素i
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) { // 从i结点的左子结点开始,也就是2i+1处开始
            if (k + 1 < length && arr[k] < arr[k + 1]) { // 如果左子结点小于右子结点,k指向右子结点
                k++;
            }
            if (arr[k] > temp) { // 如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
        }
        arr[i] = temp; // 将temp值放到最终的位置
    }

    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

 五、方法评价 

  1. 时间复杂度:堆排序的时间复杂度是O(nlogn),其中n是待排序数组的长度。构建堆的时间复杂度是O(n),每次调整堆的时间复杂度是O(logn),共需要进行n-1次调整。因此,总的时间复杂度为O(nlogn)。

  2. 空间复杂度:堆排序的空间复杂度为O(1),即不需要额外的空间进行排序。

  3. 稳定性:堆排序是一种不稳定的排序算法。在交换堆顶和末尾元素的过程中,可能会改变相同元素的相对顺序。

  4. 原地排序:堆排序是一种原地排序算法,即不需要额外的辅助空间。

 结语 

容易实现的那不叫梦想

轻言放弃的算不上努力

想成功,先发疯,不顾一切向前冲

!!!

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

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

相关文章

在VS Code中快速生成Vue模板的技巧

配置vue.json: { "Print to console": {"prefix": "vue","body": ["<template>"," <div class\"\">\n"," </div>","</template>\n","<scri…

[DDR4] 总目录 学习路线

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 传送门: 总目录 目录 基础篇 1-1 DDR4 发展历史 1-2 DDR4 和 DDR3 差异与优势 1-3 DDR4 内部结构 1-4 DDR4 工作原理 协议篇 2-1 DDR4 引脚 设计篇 实践篇 进阶篇 学习路线&#xff1a; 了解DDR4的基本知识…

AI赋能软件测试

AI赋能软件测试 AI赋能软件测试软件测试分类软件质量模型:用来衡量软件质量的维度AI赋能软件测试 随着AI时代的到来,如何轻松掌握软件测试新趋势,将AI技术应用于软件测试行业,提高测试速度与测试效率~~ 传智星云AI助手:https://nebula.itcast.cn tips:各种AI工具应有尽有…

一款经典BUCK DCDC降压芯片TPS5430适合24V转5V转12V及其电路图

前言&#xff1a; TPS5430封装和丝印 经典老款DCDC&#xff0c;适合24V转5V、24V转12V及其它24V转其它电压降压使用&#xff0c;对于输入电压较低&#xff0c;如输入12V电压的&#xff0c;不推荐使用该芯片&#xff0c;该芯片出现时间较长&#xff0c;且非同步整流芯片&#xf…

【YashanDB知识库】PHP使用ODBC使用数据库绑定参数功能异常

【问题分类】驱动使用 【关键字】ODBC、驱动使用、PHP 【问题描述】 PHP使用PDO_ODBC连接yashan数据库&#xff0c;使用绑定参数获取数据时&#xff0c;客户现场出现报错 本地复现未出现异常报错&#xff0c;但是无法正确获取数据。 【问题原因分析】开启ODBC报错日志后&am…

【计算机网络仿真实验-实验2.6】带交换机的RIP路由协议

实验2.6 带交换机的rip路由协议 1. 实验拓扑图 2. 实验前查看是否能ping通 不能 3. 三层交换机配置 switch# configure terminal switch(config)# hostname s5750 !将交换机更名为S5750 S5750# configure terminal S5750(config)#vlan 10 S5750(config-vlan)#exit S57…

【elementui源码解析】如何实现自动渲染md文档-第四篇

目录 1.前言 2.md-loader - index.js 1&#xff09;md.render() 2&#xff09;定义变量 3&#xff09;while stripTemplate stripScript genInlineComponentText 4&#xff09;pageScript 5&#xff09;return 6&#xff09;demo-block 3.总结 所有章节&#x…

React@16.x(29)useRef

目录 1&#xff0c;介绍2&#xff0c;和 React.createRef() 的区别3&#xff0c;计时器的问题 目前来说&#xff0c;因为函数组件每次触发更新时&#xff0c;都会重新运行。无法像类组件一样让一些内容保持不变。 所以才出现了各种 HOOK 函数&#xff1a;useState&#xff0c;u…

CCAA质量管理【学习笔记】​​ 备考知识点笔记(二)

第三节 GB/T19001-2016 标准正文 本节为ISO9001:2015 标准条款的正文内容&#xff0c;各条款中的术语参照上节内容理解时&#xff0c;会很轻松。本节不再一一对各条款讲解。 引 言 0.1 总 则 采用质量管理体系是组织的一项战略决策&#xff0c;能够帮助其提高整体绩效…

C++11移动语义

前言 之前我们已经知道了在类里开辟数组后&#xff0c;每一次传值返回和拷贝是&#xff0c;都会生成一个临时变量 class Arr { public://构造Arr() {/*具体实现*/ };//拷贝Arr(const Arr& ar) {/*具体实现*/ };//重载Arr operator(const Arr& ar) { /*具体实现*/Arr …

北方工业大学24计算机考研情况,学硕专硕都是国家线复试!

北方工业大学&#xff08;North China University of Technology&#xff0c;NCUT&#xff09;&#xff0c;简称“北方工大”&#xff0c;位于北京市&#xff0c;为一所以工为主、文理兼融&#xff0c;具有学士、硕士、博士培养层次的多科性高等学府&#xff0c;是中华人民共和…

自动化数据驱动?最全接口自动化测试yaml数据驱动实战

前言 我们在做自动化测试的时候&#xff0c;通常会把配置信息和测试数据存储到特定的文件中&#xff0c;以实现数据和脚本的分离&#xff0c;从而提高代码的易读性和可维护性&#xff0c;便于后期优化。 而配置文件的形式更是多种多样&#xff0c;比如&#xff1a;ini、yaml、…

Android 工程副总裁卸任

Android 工程副总裁卸任 Android工程副总裁Dave Burke宣布&#xff0c;他将辞去领导Android工程的职位&#xff0c;将重心转向“AI/生物”项目。不过&#xff0c;他并没有离开Alphabet&#xff0c;目前仍将担任Android系统开发顾问的角色。 Burke参与了Android系统的多个关键…

Vue45-分析脚手架结构

一、脚手架项目结构一览 二、src、public文件夹外的文件 2-1、babel.config.js文件 详细的配置规格&#xff1a;babel官网。 2-2、package.json包的说明书 build命令&#xff1a;代码写完了&#xff0c;最后使用build命名构建整个工程&#xff0c;将其变成浏览器能够运行的项…

【Ardiuno】实验使用ESP32单片机根据光线变化控制LED小灯开关(图文)

今天小飞鱼继续来实验ESP32的开发&#xff0c;这里使用关敏电阻来配合ESP32做一个我们平常接触比较多的根据光线变化开关灯的实验。当白天时有太阳光&#xff0c;则把小灯关闭&#xff1b;当光线不好或者黑天时&#xff0c;自动打开小灯。 int value;void setup() {pinMode(34…

虚拟机上安装centos7

目录 1&#xff0c;下载centos镜像2&#xff0c;在VMware中新建虚拟机3&#xff0c;为新创建的虚拟机挂载镜像4&#xff0c;安装centos75&#xff0c;配置网络 1&#xff0c;下载centos镜像 直接下载地址 https://mirrors.tuna.tsinghua.edu.cn/centos-vault/7.8.2003/isos/x8…

定个小目标之刷LeetCode热题(20)

这题与上一题有一点不同&#xff0c;上一题是判断链表是否存在环&#xff0c;这题是寻找入环的第一个节点&#xff0c;有一个规则是这样的&#xff0c;在存在环的情况下&#xff0c;运用快慢指针判断是否有环结束时&#xff0c;把快指针指向头结点&#xff0c;慢指针不变&#…

【Linux】进程控制1——进程创建和进程终止

1.进程创建 1.1.再谈fork 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 #include <unistd.h> pid_t fork(void);//pid_t为整形 返回值&#xff1a;子进程中的fork()返回0&#xff…

为什么电源滤波器中的电容器太大

所有 AC-DC 转换器&#xff0c;无论是线性电源还是具有某种开关元件&#xff0c;都需要一种机制来获取交流侧的变化功率并在直流侧产生恒定功率。通常&#xff0c;大滤波电容器用于在交流功率高于直流负载所需时吸收和存储能量&#xff0c;并在交流功率低于所需时向负载提供能量…