堆排序(Heap Sort)
工作原理
堆排序是一种基于堆数据结构的比较排序算法。堆是一种特殊的完全二叉树结构,其中父节点的键总是大于或小于其子节点的键。堆排序利用最大堆(或最小堆)来逐步构建有序数组。
- 构建最大堆:将给定数组转换成最大堆。
- 移除最大元素:将堆顶元素(即最大元素)与堆的最后一个元素交换,并调整剩余的堆以保持最大堆的性质。
- 重复步骤2:不断移除最大元素并调整堆,直到堆为空。
Java实现
public class HeapSort {
/**
* 堆排序算法
* @param arr 要排序的数组
*/
public static void sort(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--) {
// 移动当前根到数组末尾
swap(arr, i, 0);
// 调整剩余堆以保持最大堆的性质
heapify(arr, i, 0);
}
}
/**
* 调整堆以保持最大堆的性质
* @param arr 数组
* @param n 堆的大小
* @param i 当前节点的索引
*/
private static void heapify(int[] arr, int n, int 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) {
swap(arr, i, largest);
// 递归调整受影响的子树
heapify(arr, n, largest);
}
}
/**
* 交换数组中的两个元素
* @param arr 数组
* @param i 第一个元素的索引
* @param j 第二个元素的索引
*/
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 打印数组中的元素
* @param arr 数组
*/
public static void printArray(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
/**
* 主函数
* @param args 命令行参数
*/
public static void main(String[] args) {
int[] sampleArray = {64, 34, 25, 12, 22, 11, 90};
System.out.println("Original array:");
printArray(sampleArray);
sort(sampleArray);
System.out.println("Sorted array:");
printArray(sampleArray);
}
}
代码解析
- sort() 方法:这是堆排序的核心实现。它接受一个整型数组作为参数,并对其进行排序。
- 构建最大堆:通过
heapify()
方法将数组转换成最大堆。 - 移除最大元素:将堆顶元素(即最大元素)与堆的最后一个元素交换,并调整剩余的堆以保持最大堆的性质。
- heapify() 方法:用于调整堆以保持最大堆的性质。
- swap() 方法:用于交换数组中的两个元素。
- printArray() 方法:用于打印数组中的元素。
- main() 方法:测试排序功能的方法。
注意事项
- 时间复杂度:堆排序的时间复杂度为 O(n log n),无论是在最好、平均还是最坏情况下。
- 稳定性:堆排序是不稳定的排序算法,因为相等的元素可能会在排序过程中改变它们原有的顺序。
- 空间复杂度:堆排序的空间复杂度为 O(1),因为它不需要额外的存储空间。
适用场景
堆排序适用于大规模数据集的排序任务。由于其 O(n log n) 的时间复杂度,堆排序在处理大量数据时非常高效。此外,由于它是原地排序算法,所以在内存受限的情况下也非常有用。
希望这段代码及其说明能够帮助您更好地理解和实现堆排序算法。如果您有任何疑问或需要进一步的帮助,请随时告诉我。
评论区