堆排序
什么是堆结构?
- 堆结构是一种树结构,准确说是一种完全二叉树结构。树中的每一个结点对应着原始数据的一个记录,每个结点应满足:
- 大顶堆:从小到大排列,要求非叶结点的数据要大于等于其左右结点的数据
- 小顶堆:从大到小排列,要求非叶结点的数据要小于等于其左右结点的数据
- 由此可知,如果按照从小到大输出数据时,堆结构的根节点为要求的最大值。
如何进行堆排序?
- 步骤:构造堆结构+堆排序输出
-1. 构造堆结构
- 将所有的无序数据放到完全二叉树的各个节点中,然后将其构造成堆结构,即非叶节点的值大于其左右结点的值。根节点的值为最大。
-2. 堆排序输出
- 将根节点和末尾元素进行交换,此时末尾元素为最大值。最后将剩余的n-1个元素重复执行这个过程,即先将剩余的n-1个元素构造成一个堆,再与末尾元素交换,得到n个元素的次小值并输出,以此类推得到最终结果。
- 堆排序举例:
假设有n个需要排序的数据序列,使用堆排序将他们按照从小到大的顺序进行排序。
- 分析:
- 1.构造初始堆:将无序的序列构造为一个大顶堆(一般升序使用大顶堆,降序使用小顶堆)
- 2.将堆顶元素和末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与当前堆的末尾元素进行交换得到第二大元素,如此循环往复,最终得到结果
实现:
package com.linchong.sorttest;
public class HeapDemo {
static final int SIZE = 10;
static void HeapSort(int[] arr, int n) {
int i, j, k;
//1.构造大顶堆
for (i = n / 2 - 1; i >= 0; i--) {
while (2 * i + 1 < n) { // 第i个结点有左子树
j = 2 * i + 1;
if (j + 1 < n) { // 第i个结点有右子树
if (arr[j] < arr[j + 1])
j++;
}
if (arr[i] < arr[j]) {
swap(arr, i, j);
i = j; // 改变,堆被破坏,重新调整
} else {
break;
}
}
}
// 2.堆排序输出,重新调整堆结构
for (i = n - 1; i > 0; i--) {
swap(arr, i, 0);
k = 0;
while (2 * k + 1 < i) { // 调整堆结构
j = 2 * k + 1;
if (j + 1 < i) { // 有右子树
if (arr[j + 1] > arr[j])
j++;
}
if (arr[k] < arr[j]) {
swap(arr, k, j);
k = j; // 堆结构改变,重新调整堆结构
} else {
break;
}
}
}
}
static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
public static void main(String[] args) {
int[] array = new int[SIZE];
int i;
for (i = 0; i < SIZE; i++) {
array[i] = (int) (100 + Math.random() * (100 + 1));
}
System.out.println("排序前的数组为:");
for (int j : array) {
System.out.print(j + " ");
}
System.out.printf("\n");
HeapSort(array, SIZE);
System.out.println("排序后的数组为:");
for (int k : array) {
System.out.print(k + " ");
}
}
}