堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。堆是一个近似完全二叉树的结构,满足堆属性:即对于最大堆,任何一个节点的值都大于或等于其子节点的值;对于最小堆,任何一个节点的值都小于或等于其子节点的值。
下面的代码例子展示了堆排序的实现,包括构建最大堆、堆排序主函数和辅助函数:
// Java 实现的堆排序
public class HeapSort {
// 主函数,用于对输入数组进行排序
public 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--) {
// 将当前根(最大值)移到数组末尾
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 对缩小后的堆进行堆化处理
heapify(arr, i, 0);
}
}
// 辅助函数,用于维护堆属性
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) {
int swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
// 递归地对受影响的子树进行堆化
heapify(arr, n, largest);
}
}
// 测试函数
public static void main(String args[]) {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = arr.length;
HeapSort ob = new HeapSort();
ob.sort(arr);
System.out.println("排序后的数组是:");
printArray(arr);
}
// 用于打印数组
static void printArray(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
代码解析:
-
构建最大堆: 在
sort
方法中,我们首先从第一个非叶子节点开始,从右到左从下到上地对每个节点调用heapify
方法,这样就能将输入数组构建成一个最大堆。 -
堆排序: 通过从数组的最后一个元素开始,逐步将根节点(最大值)与当前元素交换,然后对缩小后的堆进行堆化,从而使数组从小到大排序。
-
堆化(heapify):
heapify
方法用于维护堆属性。它通过比较父节点与其子节点的大小,如果子节点大于父节点,则交换它们的位置,并递归地对受影响的子树进行堆化。 -
打印数组:
printArray
方法用于输出排序后的数组。
第二个代码例子
这里是另一个堆排序的实现例子,这次使用最小堆来进行排序:
// Java 实现的最小堆排序
public class MinHeapSort {
// 主函数,用于对输入数组进行排序
public 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--) {
// 将当前根(最小值)移到数组末尾
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 对缩小后的堆进行堆化处理
heapify(arr, i, 0);
}
}
// 辅助函数,用于维护最小堆属性
void heapify(int arr[], int n, int i) {
int smallest = i; // 初始化为根节点
int left = 2 * i + 1; // 左子节点
int right = 2 * i + 2; // 右子节点
// 如果左子节点比根节点小
if (left < n && arr[left] < arr[smallest]) {
smallest = left;
}
// 如果右子节点比当前最小值小
if (right < n && arr[right] < arr[smallest]) {
smallest = right;
}
// 如果最小值不是根节点,则交换它们
if (smallest != i) {
int swap = arr[i];
arr[i] = arr[smallest];
arr[smallest] = swap;
// 递归地对受影响的子树进行堆化
heapify(arr, n, smallest);
}
}
// 测试函数
public static void main(String args[]) {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = arr.length;
MinHeapSort ob = new MinHeapSort();
ob.sort(arr);
System.out.println("排序后的数组是:");
printArray(arr);
}
// 用于打印数组
static void printArray(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
代码解析:
-
构建最小堆: 在
sort
方法中,我们首先从第一个非叶子节点开始,从右到左从下到上地对每个节点调用heapify
方法,这样就能将输入数组构建成一个最小堆。 -
堆排序: 通过从数组的最后一个元素开始,逐步将根节点(最小值)与当前元素交换,然后对缩小后的堆进行堆化,从而使数组从大到小排序。
-
堆化(heapify):
heapify
方法用于维护最小堆属性。它通过比较父节点与其子节点的大小,如果子节点小于父节点,则交换它们的位置,并递归地对受影响的子树进行堆化。
通过这两个例子,我们可以看到堆排序的主要步骤和其实现方式。堆排序的时间复杂度为O(n log n),它是一种不稳定的排序算法,但它的空间复杂度为O(1),因为它是就地排序(in-place sorting)。