个人博客:www.hellocode.top
Java知识导航:Java-Navigate
CSDN:HelloCode.
知乎:HelloCode
掘金:HelloCode
⚡如有问题,欢迎指正,一起学习~~
堆排序是一种高效的排序算法,基于堆数据结构实现。堆是一种特殊的树状结构,具有以下特点:父节点的值大于等于(或小于等于)其子节点的值。堆排序利用堆的性质,将数组看作一个完全二叉树,通过构建最大堆(或最小堆),实现对数组的排序。
这里采用五分钟学算法大佬的图解,十分清晰
需要掌握的部分知识:
2*i + 1
,右子节点为:2*i + 2
,最后一个非叶子节点计算公式为n/2 - 1
(n为节点总数,i为当前节点索引)这里的难点就是对应的概念和计算,拿到待排序数组后,首先需要将其构建为大顶堆(或小顶堆),然后需要进行相应的节点交换,并继续调整结构使其保持大顶堆(或小顶堆)特性,代码层面还需要配合动画多多理解
相比之前的几种排序,堆排序就相对复杂一些,需要用到递归的思想。遇到递归,还是要考虑递归的出口,避免无休止的递归,这里使用递归就是不断调整来维持堆结构,自上而下递归,那么递归的出口就是到叶子节点(不能超出数组范围)。
主要分为三个方法:heapSort(对外提供的堆排序方法)、buildMaxHeap(构建初始堆结构方法)、heapify(真正调整堆结构、维持堆规则的方法)
package top.hellocode;
import java.util.Arrays;
/**
* @author HelloCode
* @blog https://www.hellocode.top
* @date 2023年08月13日 20:01
*/
public class HeapSort {
public static void main(String[] args) {
int[] arr = {19, 23, 13, 7, 84, 66, 98, 78, 54, 32, 23, 77, 88, 17};
System.out.println("排序前:" + Arrays.toString(arr));
heapSort(arr);
System.out.println("排序后:" + Arrays.toString(arr));
}
public static void heapSort(int[] arr) {
// 构建初始堆结构(默认大顶堆,实现升序排序)
buildMaxHeap(arr, arr.length);
// 开始排序
// 从堆顶取出元素,并和最后一个元素进行交换,并不断调整维持堆结构
for (int i = arr.length - 1; i > 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
heapify(arr, 0, i);
}
}
// 构建初始最大堆
private static void buildMaxHeap(int[] arr, int length) {
// 构建大顶堆,从最后一个非叶子节点开始((length - 1) / 2)
for (int i = length / 2 - 1; i >= 0; i--) {
heapify(arr, i, length);
}
}
/**
* 调整堆结构,使其成为最大堆
* int[] arr:待调整数组
* int index:子树根节点(从哪里开始向下调整)
* int length:数组长度,主要用来判断子树递归是否到达了叶子节点(超出数组长度)
*/
private static void heapify(int[] arr, int index, int length) {
// 默认假设当前子树根节点为最大值,寻找左右子节点是否有更大值
int max = index;
int left = 2 * index + 1;
int right = 2 * index + 2;
// 递归终止条件(出口)
if (left >= length || right >= length) {
return;
}
// 开始比较左右子节点
if (arr[left] > arr[max]) {
max = left;
}
if (arr[right] > arr[max]) {
max = right;
}
// 如果最大值发生了变化,则进行交换
// 只要是有交换发生,就需要对其子树继续进行递归调整
if (max != index) {
int temp = arr[index];
arr[index] = arr[max];
arr[max] = temp;
// 继续对其子树递归调整
heapify(arr, max, length);
}
}
}
测试:
排序前:[19, 23, 13, 7, 84, 66, 98, 78, 54, 32, 23, 77, 88, 17]
排序后:[7, 13, 17, 19, 23, 23, 32, 54, 66, 77, 78, 84, 88, 98]
堆排序的核心是构建堆和调整堆,可以通过一些优化来提升性能。
堆排序适用于大规模数据的排序,尤其在需要稳定排序时(如堆顶元素是最大值时)。虽然实现相对复杂,但其高效性使其成为处理大量数据的有力工具。在实际应用中,堆排序在需要高性能排序时可能是一个不错的选择。
当使用堆排序时,应特别注意其时间和空间复杂度的说明是基于固定的数据集。在实际情况中,堆排序的性能可能因为一些特定因素而有所不同,因此在特定情况下堆排序可能表现更好。