JAVA十大排序算法之堆排序详解

JAVA十大排序算法之堆排序详解

什么是堆排序

堆排序是一种经典的排序算法,在java的Collections.sort()方法中也采用了堆排序的实现方式。堆排序的基本思想是将待排序的序列视为一棵完全二叉树,每个节点的关键字都不大于(或不小于)其子节点的关键字,然后构建大(小)顶堆,最后依次取出堆顶元素并删除。

堆排序的原理

1.构建堆

堆排序首先需要将待排序的序列构建成一个堆。若是要对序列进行升序排序,则需要构建大顶堆;若是要对序列进行降序排序,则需要构建小顶堆。构建堆的过程一般采用从下往上的方式进行。

假设待构建的序列为A,该序列的长度为n,则A的最后一个非叶子节点为i=n/2-1。如果节点i的子节点存在,则节点i的左子节点为2i+1,右子节点为2i+2。从i开始循环,每次循环都是从父节点、左子节点、右子节点中找出最大值或最小值并交换位置,直到循环到根节点就结束,最终得到的堆就是大顶堆或小顶堆。

示例:

private static void buildMaxHeap(int[] arr) {  
    int n = arr.length;  
    for (int i = n/2-1; i >= 0; i--) {  
        maxHeapify(arr, n, i);  
    }  
}  

private static void maxHeapify(int[] arr, int n, int i) {  
    int left = 2 * i + 1;  
    int right = 2 * i + 2;  
    int largest = i;  
    if (left < n && arr[left] > arr[largest]) {  
        largest = left;  
    }  
    if (right < n && arr[right] > arr[largest]) {  
        largest = right;  
    }  
    if (largest != i) {  
        int temp = arr[i];  
        arr[i] = arr[largest];  
        arr[largest] = temp;  
        maxHeapify(arr, n, largest);  
    }  
}  

上面是对升序排列的堆排序的构建堆的函数实现。这里采用的是从下往上的方式,通过调用maxHeapify函数依次构建每一个堆,以最终构建好整个序列的堆。

2.取堆顶并删除

构建好一个堆之后,堆顶元素就是序列中最大的(或最小的)元素了。我们先将堆顶的元素与序列的最后一个元素交换位置,然后将序列的长度减一,这样原先的堆顶元素就被从堆中删除,并将其加入到了序列的"有序区间"中。最后,再用新的堆顶元素跟剩下的序列元素重新构建堆,重复以上步骤,直到所有元素都被从堆中删除并加入到序列的有序区间中。这就是堆排序的核心算法。

示例:

private static void heapSort(int[] arr) {  
    int n = arr.length;  
    // 构建堆(升序用大顶堆,降序用小顶堆)
    buildMaxHeap(arr);  
    for (int i = n - 1; i >= 0; i--) {  
        // 把堆顶元素与最后一个元素交换位置
        int temp = arr[0];  
        arr[0] = arr[i];  
        arr[i] = temp;  
        // 删掉堆顶元素,重新构建堆
        maxHeapify(arr, i, 0);  
    }  
}  

上面是堆排序的完整代码实现。此处先构建大顶堆用于升序排列,然后循环依次取出堆顶元素,并删除。每次删除之后都需要重新构建堆,从而得到新的堆顶元素,然后再次取出、删除,如此循环迭代,最终完成排序操作。

注意事项

  1. 堆排序的时间复杂度为O(nlogn),空间复杂度为O(1)。
  2. 堆排序不稳定,可能破坏稳定性。
  3. 堆排序在序列长度较小时,被认为是不如其他排序算法的。
  4. 堆排序虽然时间复杂度比较高,但是实现起来相对简单。

总结

堆排序是比较经典的排序算法之一。它采用的是构建堆和取堆顶并删除的方式,经过多次循环迭代,最终得到有序序列。虽然时间复杂度比较高,但是实现起来相对比较简单,而且不像快速排序、冒泡排序等算法会受到数据初始排列的影响,因此具有比较稳定的性能。但是,堆排序由于是不稳定的,所以在某些场景下可能不是最佳的选择。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JAVA十大排序算法之堆排序详解 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Java缓存技术的作用是什么?

    Java缓存技术是在应用程序和数据库之间的一种中间层,用于存储暂时性数据,尤其是读取频繁但更新较少的数据。它的作用是减轻应用程序和数据库之间的负担,提高应用程序的响应速度和性能。下面我们将详细介绍如何使用Java缓存技术。 1. 选择合适的Java缓存框架 Java缓存框架有很多种,常见的有Guava Cache、Ehcache、Redis等。根据应用的不同…

    Java 2023年5月11日
    00
  • Springboot es包版本异常解决方案

    下面是“Springboot es包版本异常解决方案”的完整攻略,包含以下几部分内容: 问题描述 解决方案 示例说明 问题描述 使用 Spring Boot 时,如果要使用 Elasticsearch,一般会使用 Spring Data Elasticsearch(spring-boot-starter-data-elasticsearch),其中包含了 E…

    Java 2023年5月27日
    00
  • Java 泛型详解(超详细的java泛型方法解析)

    Java泛型详解 什么是泛型? 泛型主要体现在类和方法中,用于实现在编译时期进行类型检查和类型推断的功能,从而避免了在运行时出现类型转换的错误。 泛型类 泛型类是指在类的定义中使用了泛型,即类中的属性、方法等都可以使用泛型。泛型类的语法格式如下: class ClassName<T1, T2, …> { //属性的类型也可以使用泛型 T1 a…

    Java 2023年5月23日
    00
  • 如何进行Java性能调优?

    如何进行Java性能调优? Java性能调优主要是通过一系列的措施来减少应用程序消耗的资源,提高程序的性能。一般通过以下几个步骤来进行Java性能调优: 分析异常现象和性能问题,并定位问题根源 首先需要收集一些关键指标以判断Java应用程序的健康状况。例如:CPU使用率、内存使用率、线程数、网络I/O等等。然后根据这些指标,在出现异常或性能瓶颈的时候,对应用…

    Java 2023年5月11日
    00
  • Java下载文件的四种方式详细代码

    下面我将为您详细讲解Java下载文件的四种方式和完整代码。 一、使用Java自带的URL类进行文件下载 使用Java自带的URL类可以方便地进行文件下载,步骤如下: 创建一个URL对象,指定需要下载的文件链接。 打开 URL 连接,获取 InputStream 对象,用于读取远程文件流。 创建文件输出流对象,用于保存下载的文件。 读取远程文件并将其写入到本地…

    Java 2023年5月20日
    00
  • Java实现简单扫雷程序

    Java实现简单扫雷程序的攻略大致可以分为以下几个步骤: 第一步:分析游戏需求,设计类和逻辑 在设计Java扫雷程序时,我们需要考虑到以下问题: 扫雷窗口的界面是怎样的,需要显示哪些控件? 扫雷窗口需要响应哪些鼠标和键盘事件? 扫雷窗口需要记录哪些状态信息? 回答了上述问题,便可开始设计类和逻辑。常见的类有Minesweeper窗口、Minesweeper游…

    Java 2023年5月19日
    00
  • java 获取当前路径下的所有xml文档的方法

    让我们来详细讲解如何用java代码获取指定目录下的所有以xml结尾的文件。 1. 获取当前路径 首先,我们需要获取当前路径,即指定目录所在的路径。可以使用System.getProperty()方法获取系统属性中的当前路径。 String currentPath = System.getProperty("user.dir"); Syst…

    Java 2023年5月19日
    00
  • springboot返回前端中文乱码的解决

    下面是详细的“springboot返回前端中文乱码的解决”的攻略: 问题产生的原因 在SpringBoot中,我们通常使用@RestController注解来声明一个RESTful风格的控制器,同时还使用了@RequestParam来获取前端传入的中文参数。然而,当我们返回中文字符串给前端时,很容易遇到返回结果乱码的问题。这是因为SpringBoot默认使用…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部