【算法系列 | 6】深入解析排序算法之——堆排序

news2024/11/17 6:02:22

 

序言

你只管努力,其他交给时间,时间会证明一切。

文章标记颜色说明:

  • 黄色:重要标题
  • 红色:用来标记结论
  • 绿色:用来标记一级论点
  • 蓝色:用来标记二级论点

决定开一个算法专栏,希望能帮助大家很好的了解算法。主要深入解析每个算法,从概念到示例。

我们一起努力,成为更好的自己!

今天第3讲,讲一下排序算法的堆排序(Heap Sort)

1 基础介绍

排序算法是很常见的一类问题,主要是将一组数据按照某种规则进行排序。

以下是一些常见的排序算法:

  1. 冒泡排序(Bubble Sort)

  2. 插入排序(Insertion Sort)

  3. 选择排序(Selection Sort)

  4. 归并排序(Merge Sort)

  5. 快速排序(Quick Sort)

  6. 堆排序(Heap Sort)

一、堆排序介绍

1.1 原理介绍

堆排序(Heap Sort)是一种基于堆数据结构的排序算法,其核心思想是将待排序的序列构建成一个最大堆(或最小堆),然后将堆顶元素与最后一个元素交换,再将剩余元素重新调整为最大堆(或最小堆),重复以上步骤直到所有元素都有序。

堆是一种特殊的二叉树,满足以下两个条件:

  1. 堆是一棵完全二叉树,即除了最后一层,其他层都是满的,最后一层的节点都靠左排列。

  2. 对于最大堆,任何一个父节点的值都大于(或等于)其左右子节点的值,对于最小堆,则是任何一个父节点的值都小于(或等于)其左右子节点的值。

堆排序的实现过程如下:

  1. 构建堆:首先将待排序的序列构建成一个最大堆(或最小堆),可以从最后一个非叶子节点开始,从右至左,从下至上依次将每个节点调整为符合堆的性质。

  2. 堆排序:将堆顶元素与最后一个元素交换,然后将剩余元素重新调整为最大堆(或最小堆),再次将堆顶元素与倒数第二个元素交换,如此循环直到排序完成。

细节讲解 

具体的实现细节如下:

  1. 构建堆:从最后一个非叶子节点开始,依次将每个节点调整为符合堆的性质。对于一个节点,如果它的左右子节点中有一个大于(或小于)该节点,则交换它们的位置,然后递归调用该节点所在的子树,直到该节点不再有子节点或者其子节点都满足堆的性质为止。

  2. 堆排序:将堆顶元素与最后一个元素交换,然后将剩余元素重新调整为最大堆(或最小堆),再次将堆顶元素与倒数第二个元素交换,如此循环直到排序完成。

1.2 复杂度 

堆排序:

  • 时间复杂度为 $O(n\log n)$
  • 空间复杂度为 $O(1)$

相对于其他的排序算法,其实现简单,但需要额外的空间来存储堆数据结构。

1.3使用场景

堆排序使用场景堆排序的使用场景与其他排序算法类似,适用于需要对大量数据进行排序的场景。

1.4 优缺点 

优点:

其优点主要包括:

  1. 时间复杂度较低:堆排序的时间复杂度为 $O(n\log n)$,相对于其他排序算法,其排序速度较快。

  2. 不占用额外空间:堆排序是一种原地排序算法,不需要额外的空间来存储排序结果。

  3. 适用于大数据量的排序:堆排序的时间复杂度不随数据量的增加而变化,因此适用于大数据量的排序。

缺点:

堆排序的缺点主要包括:

  1. 不稳定性:由于堆排序是通过交换元素来实现排序的,因此在排序过程中可能会破坏原有的相对顺序,导致排序结果不稳定。

  2. 实现复杂:相对于其他排序算法,堆排序的实现稍微复杂一些,需要理解堆数据结构的基本原理和实现过程。

因此,堆排序适用于需要对大量数据进行排序的场景特别是在数据量较大、内存有限的情况下,堆排序可以通过原地排序的方式,节省额外空间的使用

二、代码实现

2.1 Python 实现

下面是 Python 实现堆排序的示例代码:

def heap_sort(arr):
    n = len(arr)
    
    # 构建最大堆
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)
    
    # 排序
    for i in range(n - 1, 0, -1):
        # 将堆顶元素与最后一个元素交换
        arr[0], arr[i] = arr[i], arr[0]
        # 调整剩余元素为最大堆
        heapify(arr, i, 0)

def heapify(arr, n, i):
    # 将以 i 为根节点的子树调整为最大堆
    largest = i  # 初始化最大元素为根节点
    left = 2 * i + 1  # 左子节点的索引
    right = 2 * i + 2  # 右子节点的索引

    # 找出左右子节点中的最大值
    if left < n and arr[left] > arr[largest]:
        largest = left
    if right < n and arr[right] > arr[largest]:
        largest = right

    # 如果最大值不是根节点,则交换根节点和最大值,并递归调整子树
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

测试

下面是 Python 实现堆排序的测试代码:

arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]

print("Before sorting:", arr)
heap_sort(arr)
print("After sorting:", arr)

在上面的测试代码中,定义了一个整数数组 arr,并将其传递给 heap_sort 函数进行排序。

排序完成后,使用 print 函数将排序后的数组输出到控制台。运行测试代码,将得到以下输出结果:

Before sorting: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
After sorting: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]

可以看到,排序后的数组已经按照从小到大的顺序排列。

2.2Java实现

下面是 Java 实现堆排序的示例代码:

public static void heapSort(int[] arr) {
    int n = arr.length;

    // 构建最大堆
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(arr, n, i);
    }

    // 排序
    for (int i = n - 1; i > 0; i--) {
        // 将堆顶元素与最后一个元素交换
        int tmp = arr[0];
        arr[0] = arr[i];
        arr[i] = tmp;

        // 调整剩余元素为最大堆
        heapify(arr, i, 0);
    }
}

public static void heapify(int[] arr, int n, int i) {
    // 将以 i 为根节点的子树调整为最大堆
    int largest = i;  // 初始化最大元素为根节点
    int left = 2 * i + 1;  // 左子节点的索引
    int right = 2 * i + 2;  // 右子节点的索引

    // 找出左右子节点中的最大值
    if (left < n && arr[left] > arr[largest]) {
        largest = left;
    }
    if (right < n && arr[right] > arr[largest]) {
        largest = right;
    }

    // 如果最大值不是根节点,则交换根节点和最大值,并递归调整子树
    if (largest != i) {
        int tmp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = tmp;
        heapify(arr, n, largest);
    }
}

测试

下面是 Java 实现堆排序的测试代码:

import java.util.Arrays;

public class HeapSortTest {
    public static void main(String[] args) {
        int[] arr = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };

        System.out.println("Before sorting: " + Arrays.toString(arr));
        heapSort(arr);
        System.out.println("After sorting: " + Arrays.toString(arr));
    }
}

在上面的测试代码中,定义了一个整数数组 arr,并将其传递给 heapSort 方法进行排序。排序完成后,使用 Arrays.toString 方法将排序后的数组输出到控制台。

运行测试代码,将得到以下输出结果:

Before sorting: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
After sorting: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]

可以看到,排序后的数组已经按照从小到大的顺序排列。

图书推荐

图书名称:

  • 精通Hadoop3
  • pandas1.X实例讲解
  • 人人都离不开的算法——图解算法应用
  • Python数据清洗

精通Hadoop3

pandas1.X实例讲解

人人都离不开的算法——图解算法应用

Python数据清洗

活动说明

   618,清华社 IT BOOK 多得图书活动开始啦!活动时间为 2023 年 6 月 7 日至 6 月 18 日,清华社为您精选多款高分好书,涵盖了 C++、Java、Python、前端、后端、数据库、算法与机器学习等多个 IT 开发领域,适合不同层次的读者。全场 5 折,扫码领券更有优惠哦!快来京东点击链接 IT BOOK 多得,查看详情吧!

活动链接:IT BOOK

​ 

参与方式 

图书数量:本次送出 3 本   !!!⭐️⭐️⭐️
活动时间:截止到 2023-06-16 12:00:00

抽奖方式:

  • 评论区随机抽取小伙伴!

留言内容,以下方式都可以:

  • 根据文章内容进行高质量评论

参与方式:关注博主、点赞、收藏,评论区留言 

中奖名单 

🍓🍓 获奖名单🍓🍓

 中奖名单:请关注博主动态

名单公布时间:2023-06-16 下午

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

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

相关文章

整理 钢琴教材 铃木钢琴教程(铃木)

邮箱不能及时回复,现放到网盘里了,文末按需自取 铃木钢琴教程第1册 文件名:铃木钢琴教程第1册 超清PDF 文件大小:7.05 MB 下载地址:https://download.csdn.net/download/qq_36040764/85051148 铃木钢琴教程第2册 文件名:铃木钢琴教程第2册 超清PDF 文件大小:5.54 …

边缘检测笔记

边缘是什么&#xff1f; 图像的边缘是指图像局部区域中亮度变化明显的部分&#xff0c;边缘位于像素的灰度值产生突变的地方。 边缘的正负之分&#xff1a;由暗到亮为正&#xff0c;由亮变暗为负。 图像的高频信号和低频信号 简单理解为&#xff0c;图像中高频分量&#xff08…

在Windows11平台安装JDK11(双11)

目录 引言一、安装前说明1.系统要求2.多版本安装 二、JDK11安装三、安装成功验证1.验证2.Path环境变量 总结 引言 本文主要是详细讲解在 Windows 11 系统上安装 JDK 11&#xff0c;安装时有一些注意事项需要说明。与 JDK 8 的安装过程有少许不一样。 一、安装前说明 1.系统要…

GPT-4的中国2023高考作文

我选取2023年上海的作文题&#xff08;我比较感兴趣&#xff09;&#xff0c;题目如下&#xff1a; 面对这个题目&#xff0c;不知道各位有什么想法么&#xff1f;如果你去考试&#xff0c;你会怎么写&#xff1f; 来&#xff0c;我们看看AI是怎么写的。 以下是GPT-4的作文&a…

vmware虚拟机网络“桥接模式”与“NAT模式”的联网原理及linux环境下IP配置指引

一、vmware虚拟机网络“桥接模式”与“NAT模式”的区别 选中虚拟机》设置》网络适配器&#xff0c;打开虚拟机设置面板 我们看到网络连接处有多个选项&#xff0c;今天良哥通过试验告诉你“桥接模式”和“NAT模式”的联网原理、区别及两种模式下IP地址配置的详细方法。 桥接模…

spring-data-elasticsearch.4.2.0 jar包冲突导致:StackOverflow

最近要求es做升级改造: 目前版本: 1. springframework 4.3.3-RELEASE 2. spring-data-elasticsearch: 2.0.3 3. elasticsearch: 2.4.0 4. 工具类: ElasticsearchTemplate 升级后ES版本7.10.0 1. springframework 升级到 5.3.10 2. spring-data-elasticsearch 升级到 4.…

热门bi报表软件推荐,哪款bi报表软件更功能更强大?

随着商业智能&#xff08;BI&#xff09;的不断发展和应用&#xff0c;越来越多的企业开始关注和使用BI报表软件。但是在众多的BI报表软件中&#xff0c;如何选择一款既功能强大又易于使用的软件&#xff0c;成为了许多企业和个人面临的难题。下面将为大家介绍5款热门的BI报表软…

爆肝百万字;学完这些你的python就无敌了

前言 最近高考刚刚结束&#xff0c;不少大学也快陆陆续续的要放暑假了&#xff0c;不少人表示暑假想学点python知识&#xff0c;或提升下自己&#xff0c;或打算学点技术兼职赚点零花钱&#xff0c;于是肝了一份Python最新学习文档总结资料 &#xff1a;全文档1378页&#xff…

Python的离线安装

原文链接 在没有外网的情况下&#xff0c;安装Python环境只能采用离线方式。 Windows离线安装Python Python离线安装包的下载地址&#xff1a;https://www.python.org/ftp/python/ 我选择的是&#xff1a;python-3.8.5-amd64.exe 双击运行安装包即可完成安装。 安装完成后…

简化本地Feign调用

在平常的工作中&#xff0c;OpenFeign作为微服务间的调用组件使用的非常普遍&#xff0c;接口配合注解的调用方式突出一个简便&#xff0c;让我们能无需关注内部细节就能实现服务间的接口调用。 但是工作中用久了&#xff0c;发现 Feign 也有些使用起来麻烦的地方&#xff0c;…

【Haproxy 搭建Web 群集】

目录 一、Haoroxy 基础了解1、常见的Web集群调度器2、Haproxy 应用分析 二、Haproxy 调度算法原理三、HAProxy的主要特性四、HAProxy负载均衡策略五、LVS、Nginx、HAproxy的区别1、Nginx的优点&#xff0c;缺点2、LVS的优点和缺点3、HAProxy的优点 六、Haproxy搭建 Web 群集实验…

跟着LearnOpenGL学习8--摄像机

文章目录 一、前言二、摄像机/观察空间2.1、摄像机位置2.2、摄像机方向2.3、右轴2.4、上轴2.5、LookAt2.6、LookAt测试 三、自由移动3.1、移动速度 四、视角移动4.1、欧拉角 五、鼠标输入5.1、缩放 六、摄像机类 一、前言 前面的教程中我们讨论了观察矩阵以及如何使用观察矩阵…

【软考系统架构师】进程与线程、并发和并行的理解

进程和线程的概念是软考里经常出现的概念&#xff0c;也是计算机领域的基础概念之一&#xff0c;看到一套非常形象的进程和线程的解释&#xff0c;记录一下 CPU 相当于一个工厂的能源核心&#xff0c;它一直运行&#xff0c;并向外提供动力。 什么是进程 但是这家工厂资金有限&…

A*算法与八数码问题(numpy)

努力是为了不平庸~ 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。 目录 一、引言 二、思路 1. 确定问题和目标&#xff1a; 2. 确定算法和数据结构&#xff1a; 3. 编写代码框架 4. 实现辅助函数&#xff1…

CreateML 使用以及机器学习基础概念

1. 前言 在学习 CreateML 之前&#xff0c;我们先了解一下什么是机器学习&#xff1f;目前还不存在被广泛认可的定义来准确定义机器学习是什么。第一个机器学习的定义来自于Arthur Samuel。他定义机器学习为&#xff0c;在进行特定编程的情况下&#xff0c;给予计算机学习能力…

C语言-类型转换

数据有不同的类型&#xff0c;不同类型数据之间进行混合运算时必然涉及到类型的转换问题. 转换的方法有两种&#xff1a; 自动转换: 遵循一定的规则,由编译系统自动完成. 强制类型转换&#xff1a; 把表达式的运算结果强制转换成所需的数据类型 1 自动转换 自动转换原则 …

阿里人手一本的Java性能调优手册,几乎涵盖了性能优化的所有操作

说起性能调优&#xff0c;想必大家都知道&#xff0c;但是就是没怎么用过&#xff0c;所以在Java性能优化上面临着很多的困扰&#xff0c;比如&#xff1a; 能力修炼中&#xff0c;由于常年接触 CRUD&#xff0c;缺乏高并发这一实践环境&#xff0c;对“性能优化”只能通过理论…

剑指 Offer 59 - I: 滑动窗口的最大值

第一眼看这个感觉思路没啥大问题&#xff0c;就是一个大循环不断后移&#xff0c;然后小循环维护一个k长度的队列。注意peekFirst和peekLast的使用&#xff0c;双端队列可以打破先进先出或者先进后出的局限性&#xff0c;因此peek没有默认值&#xff0c;得加上First或者Last来进…

干货 | 腾讯云李滨:云时代数据安全治理方法与实践

作者&#xff1a;李滨‍‍‍‍本文约2600字&#xff0c;建议阅读8分钟 本文与你分享腾旭在数据安全和人工智能的安全治理方法&#xff0c;以及实践上的一些经验。 今天很荣幸与大家分享在过去几年以内&#xff0c;腾讯在数据安全和人工智能的安全治理方法&#xff0c;以及实践上…

使用服务器的妙妙工具

为什么使用服务器&#xff1f; 一台电脑的性能终究是有限的&#xff0c;所以当计算量太大时&#xff0c;我们可以借助服务器&#xff0c;它的运算速度快&#xff0c;存储空间大。 和个人电脑不同&#xff0c;服务器通常由一个管理员进行管理&#xff0c;而有多用户同时使用。…