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日

相关文章

  • Spring boot异步任务原理全面分析

    Spring Boot异步任务原理全面分析 在Spring Boot中,我们经常需要执行一些耗时的操作,如果将它们放入主线程中进行,会导致响应变慢,用户体验不佳。而异步任务可以避免这种情况的出现。 什么是Spring Boot异步任务 Spring Boot异步任务是指在独立的线程中处理某些任务,将主线程从处理任务中解放出来的机制。Spring Boot提供…

    Java 2023年5月19日
    00
  • 消息推送平台终于要发布啦!

    我的开源项目消息推送平台Austin终于要上线了,迎来在线演示的第一版! ?项目在线演示地址:http://139.9.73.20:3000/ 消息推送平台?推送下发【邮件】【短信】【微信服务号】【微信小程序】【企业微信】【钉钉】等消息类型。 https://gitee.com/zhongfucheng/austin/ https://github.com/…

    Java 2023年5月4日
    00
  • 如何开发一个简单的Akka Java应用

    如何开发一个简单的Akka Java应用 Akka 是一个构建并发、分布式、可扩展的消息驱动应用程序的工具包与运行时。 要开发一个简单的Akka Java应用,可以按照以下步骤进行。 步骤一:添加依赖 在项目的 pom.xml 文件中添加以下依赖: <dependencies> <dependency> <groupId>…

    Java 2023年5月26日
    00
  • java反射原理制作对象打印工具

    下面详细讲解一下Java反射原理制作对象打印工具的完整攻略。 什么是Java反射? 在Java中,每个类都有一个Class对象,该对象包含了与类有关的所有信息,包括类名、访问修饰符、字段、方法等。 Java反射就是指:在运行时动态地获取一个类的Class对象,并对该类进行操作的能力。通过Java反射,我们可以在运行时动态地创建对象、调用方法、获取/设置字段的…

    Java 2023年5月26日
    00
  • java简单实现计算器

    下面是“Java简单实现计算器”的完整攻略: 1. 实现思路 Java简单实现计算器的核心是要实现对用户输入的表达式的计算,这可以通过将输入的表达式转化成中缀表达式,然后再将中缀表达式转换成后缀表达式来实现。转换成后缀表达式后,计算过程可以通过栈的数据结构来实现。 具体步骤如下: 接收用户输入的表达式。 将表达式转换成中缀表达式。 将中缀表达式转换成后缀表达…

    Java 2023年5月18日
    00
  • Java输出链表倒数第k个节点

    下面是Java输出链表倒数第k个节点的完整攻略: 理解题意意义:输入一个链表,输出该链表中倒数第k个节点的值。 考虑边界条件:输入的链表为空或k不能大于链表长度。 定义两个指针,分别指向链表头部。让其中一个从0开始,先走k步,另一个开始走。然后两个指针同步走,直到其中一个到达链表尾部。另一个指针此时就是链表倒数第k个节点。 编写代码: public List…

    Java 2023年5月26日
    00
  • JAVA实现感知器算法

    实现感知器算法可以通过Java语言来完成。下面是实现感知器算法的完整攻略: 算法简介 感知器算法是一种基础的人工神经网络算法,它的运行原理是根据学习结果对指定的输出结果进行二元决策。感知器算法能够实现二分类,也就是将输入数据划分为两类,如True和False,1和0等。以下是感知器算法的主要步骤: 初始化权重 得到输入的训练数据 计算感知器输出 根据误差调整…

    Java 2023年5月18日
    00
  • javaweb分页原理详解

    对于“javaweb分页原理详解”,以下是我整理的完整攻略: 一、分页原理介绍 1.1 分页的定义 分页是指将大容量数据均匀的分成若干页面,每页包含固定数量的信息,以便于操作。在网站开发的过程中,分页技术经常被用来显示查询结果,以减少服务器的负载和提高用户体验。 1.2 分页的实现原理 在进行分页操作时,我们需要以下信息: 当前页码 每页显示的记录数 总记录…

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