使用Java函数实现堆排序
堆排序是一种高效的排序算法,它基于数据结构中堆这一概念,利用堆的性质完成排序。在堆排序过程中,我们首先建立一个最大堆(或最小堆),然后依次从堆中取出一个元素,放入已排序的列表中,重复此过程直至堆为空。本文将使用Java函数实现堆排序算法。
实现堆排序的Java函数代码如下:
public class HeapSort {
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--) {
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 重新构建最大堆
heapify(arr, i, 0);
}
}
// 构建最大堆
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) {
int swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
heapify(arr, n, largest);
}
}
}
在上述代码中,sort函数中的 步是构建最大堆。堆的构建过程可以理解为将一个无序的数组调整为满足堆结构的数组。具体过程如下:从后往前检查每个非叶子节点,如果其子节点值大于该节点值,即构成了一个不满足堆结构的小根堆,于是将该节点与该节点的最大子孙节点交换位置,继续往下检查。如果所有非叶子节点都已经满足堆结构,则整个数组就满足了最大堆的条件。
第二步是依次从堆中取出最大元素,依次放入已排序的列表中。由于我们使用的是最大堆,所以每次取出的元素都是剩余元素中的最大值。我们将最大值放入已排序列表中,并将该位置的元素与堆的最后一个元素交换位置。此时我们需要重新构建最大堆。由于我们取出了一个元素,所以我们只需要检查剩下元素的堆结构是否满足,因此第二步中调用heapify函数时,第二个参数传入的是剩余元素的数量,即i。重新构建最大堆的过程与构建初始堆的过程类似,只不过此时我们不需要检查从后往前所有的非叶子节点。我们只需要检查根节点和其左右子节点中的最大值,如果根节点不是最大值,则交换节点位置并继续往下检查。
最后,我们来看一个堆排序的例子。假设我们有一个无序的数组:{5, 8, 7, 3, 2, 1, 6, 4}。
步,我们先构建最大堆,让数组满足堆结构的条件。所有非叶子节点都检查一遍后,该数组已经满足最大堆的条件。此时数组内容如下:
{8, 5, 7, 4, 2, 1, 6, 3}
我们发现元素8已经在堆的根节点了,满足堆的条件。
第二步,我们依次从堆中取出最大元素,并将其放入已排序的列表中。首先取出堆中的根节点8,交换位置后,数组变成了:
{3, 5, 7, 4, 2, 1, 6, 8}
此时我们需要重新构建堆,以满足堆结构的条件。检查根节点3与其左右子节点中的最大值7,交换位置后,数组变成了:
{7, 5, 3, 4, 2, 1, 6, 8}
继续从堆中取出最大元素,此时的根节点是7,取出该元素并放入已排序的列表中。交换位置后,数组变成了:
{6, 5, 3, 4, 2, 1, 7, 8}
重新构建堆,交换元素4和根节点6的位置,数组变成了:
{5, 4, 3, 2, 1, 6, 7, 8}
继续取出最大元素7,交换位置后,数组变成了:
{6, 4, 3, 2, 1, 5, 7, 8}
重新构建堆,此时元素1与根节点6进行交换,然后再次从堆中取出最大元素(即根节点6),交换位置后,数组变成了:
{5, 4, 3, 2, 1, 6, 7, 8}
重新构建堆,此时元素2与根节点5进行交换,然后再次从堆中取出最大元素(即根节点5),交换位置后,数组变成了:
{4, 2, 3, 1, 5, 6, 7, 8}
重新构建堆,此时元素1与根节点4进行交换,然后再次从堆中取出最大元素(即根节点4),交换位置后,数组变成了:
{3, 2, 1, 4, 5, 6, 7, 8}
重新构建堆,此时元素1与根节点3进行交换,然后再次从堆中取出最大元素(即根节点3),交换位置后,数组变成了:
{2, 1, 3, 4, 5, 6, 7, 8}
重新构建堆,此时元素1与根节点2进行交换,然后再次从堆中取出最大元素(即根节点2),交换位置后,数组变成了:
{1, 2, 3, 4, 5, 6, 7, 8}
此时堆为空,排序完成。
综上所述,堆排序是一种高效的排序算法,它可以在O(nlogn)的时间内完成排序。使用Java函数实现堆排序,可以方便地将该算法应用于实际开发。
