堆排序算法的讲解及Java版实现

堆排序算法的讲解及Java版实现

目录

概述

堆排序(Heap Sort)是一种选择排序,它的平均时间复杂度为 O(nlogn),实用性较高。

堆排序的基本思想是:

  1. 将待排序的序列构建成一个大顶堆(或小顶堆);
  2. 此时,整个序列的最大值(或最小值)就是堆顶的根节点;
  3. 将其与末尾元素进行交换,此时末尾就为最大值(或最小值);
  4. 然后将剩下的 n-1 个元素重新构建成一个堆,继续进行交换操作,直到整个序列有序。

堆的实现

在堆排序中,我们需要用到堆的数据结构。堆实际上是一个完全二叉树,分为大顶堆和小顶堆。

  • 大顶堆:每个节点的值都大于或等于其左右子节点的值。
  • 小顶堆:每个节点的值都小于或等于其左右子节点的值。

实现堆的时候,我们可以用一维数组来表示。假设数组的下标从 1 开始,那么对于下标为 i 的节点:

  • 左节点索引为 i * 2;
  • 右节点索引为 i * 2 + 1;
  • 父节点索引为 i / 2。

堆排序的实现

堆排序算法的思路分成两个主要的过程:

  1. 将序列构建成堆;
  2. 将堆顶元素与末尾元素交换,并且重新将剩下的元素构建成堆,重复操作直到整个序列有序。

具体实现过程:

  1. 构建大根堆(升序排序)或小根堆(降序排序),即使每个非叶子节点的值都大于或等于(或小于或等于)其子节点的值。

    1. 从后向前遍历数组,对于当前索引为 i 的元素:
      1. 将其与左右子节点中较大的那一个交换位置,直到满足堆的定义。
    2. 当整个数组都构建完毕后,堆顶元素就是最大值(或最小值)。
  2. 将堆顶元素与末尾元素进行交换,并且重新将其余元素构建成堆。

    1. 将堆顶元素与末尾元素互换位置,此时末尾就是数组中的最大值(或最小值)。
    2. 对于前面 n-1 个元素重新进行构建堆的操作。

重复上述步骤,直到整个序列有序。

Java版实现示例

public class HeapSort {
    public static void sort(int[] arr) {
        // 构建大根堆
        buildHeap(arr, arr.length - 1);
        // 从后向前遍历数组,依次将堆顶元素与末尾元素交换,并重新构建堆
        for (int i = arr.length - 1; i >= 1; i--) {
            swap(arr, 0, i); // 将堆顶元素与末尾元素交换位置
            heapify(arr, 0, i - 1); // 重新构建堆
        }
    }

    // 构建大根堆
    private static void buildHeap(int[] arr, int end) {
        for (int i = (end - 1) / 2; i >= 0; i--) {
            heapify(arr, i, end);
        }
    }

    // 以节点 i 为根的子树重新构建大根堆
    private static void heapify(int[] arr, int i, int end) {
        int left = i * 2 + 1; // 左子节点索引
        int right = i * 2 + 2; // 右子节点索引
        int max = i; // 堆的最大节点索引
        // 找到堆中最大的节点
        if (left <= end && arr[left] > arr[max]) {
            max = left;
        }
        if (right <= end && arr[right] > arr[max]) {
            max = right;
        }
        if (max != i) { // 若最大节点不是当前节点,就将其交换位置
            swap(arr, i, max);
            heapify(arr, max, end); // 对以 max 为根的子树进行堆化操作
        }
    }

    // 交换数组中下标为 i 和 j 的元素
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

示例一:对数组 {7, 6, 5, 4, 3, 2, 1} 进行堆排序(升序排列)

int[] arr = {7, 6, 5, 4, 3, 2, 1};
HeapSort.sort(arr);
System.out.println(Arrays.toString(arr)); // 输出 [1, 2, 3, 4, 5, 6, 7]

示例二:对数组 {-1, 0, 3, 5, 2, 1} 进行堆排序(降序排列)

int[] arr = {-1, 0, 3, 5, 2, 1};
HeapSort.sort(arr);
System.out.println(Arrays.toString(arr)); // 输出 [5, 3, 2, 1, 0, -1]

以上就是堆排序算法的讲解及Java版实现的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:堆排序算法的讲解及Java版实现 - Python技术站

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

相关文章

  • IntelliJ IDEA 创建 Java 项目及创建 Java 文件并运行的详细步骤

    下面是关于“IntelliJ IDEA 创建 Java 项目及创建 Java 文件并运行的详细步骤”的完整攻略: 步骤一:创建新的Java项目 打开 IntelliJ IDEA,进入欢迎界面,点击 “Create New Project”。 确认左侧栏选择 “Java”,并输入项目的名称,可以任意取。然后点击 “Next”。 在弹出的窗口中选择 “Proje…

    Java 2023年5月20日
    00
  • 一文详解Spring构造函数推断

    一文详解Spring构造函数推断 在使用Spring Framework进行Java开发时,构造函数推断是一个重要的特性。本文将介绍什么是构造函数推断,为什么需要它,以及如何使用它。 什么是构造函数推断? 构造函数推断是Spring Framework的一个特性,它可以自动推断应该使用哪个构造函数来实例化一个 bean。以前,我们需要显式地在XML或Java…

    Java 2023年5月26日
    00
  • Spring Security动态权限的实现方法详解

    Spring Security动态权限的实现方法详解 Spring Security 是一个基于 Spring 的安全框架,提供了一种基于角色的访问控制模型。但是在一些场景中,我们需要动态地控制用户的权限,这时候我们就需要实现 Spring Security 的动态权限控制。本文将详细介绍如何实现 Spring Security 动态权限的控制。 实现步骤 …

    Java 2023年6月3日
    00
  • 浅谈Spring Data Redis读不到设进去的值

    针对“浅谈Spring Data Redis读不到设进去的值”的问题,我整理了以下攻略,希望可以帮到您。 问题描述 在使用Spring Data Redis操作Redis时,发现虽然可以成功地将值设进去,但是在读取的时候却无法读取到。 原因分析 Redis中的key过期 Redis有可能设置了自动过期,导致读取不到之前存储在Redis中的值。可以通过ttl命…

    Java 2023年5月20日
    00
  • SpringBoot使用编程方式配置DataSource的方法

    当使用SpringBoot构建Web应用程序时,我们常常需要使用数据源,这里我们具体讲解使用编程方式配置DataSource的方法。 首先,需要在pom.xml文件中添加相应的依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactI…

    Java 2023年5月19日
    00
  • 基于Java的打包jar、war、ear包的作用与区别详解

    下面我将详细讲解“基于Java的打包jar、war、ear包的作用与区别详解”的完整攻略。 什么是jar、war、ear包? Java开发中,jar、war、ear包都是打包构建目标文件。其中: jar包:Java Archive,可以将Java类文件、资源文件打包到一个文件中,通常用于在命令行中运行Java应用程序或在Web服务器上部署Java Web应用…

    Java 2023年5月26日
    00
  • spring的@Transactional注解用法解读

    下面是关于“spring的@Transactional注解用法解读”的完整攻略。 什么是@Transactional注解? @Transactional是Spring框架中用于实现事务管理的注解。在一个被该注解标注的方法或类上使用该注解,可以使得这个方法或类变为一个事务处理的方法或类,在这个方法或类的执行过程中,会同步进行数据源的事务管理。 @Transac…

    Java 2023年5月20日
    00
  • spring mvc中@RequestBody注解的作用说明

    在 Spring MVC 中,@RequestBody 注解用于将 HTTP 请求体映射到一个对象上。本文将详细讲解 @RequestBody 注解的作用说明,并提供两个示例说明。 1. @RequestBody 注解的作用说明 @RequestBody 注解用于将 HTTP 请求体映射到一个对象上。当我们使用 @RequestBody 注解时,Spring…

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