堆排序概括:
堆排序(Heapsort)是指利用堆这种数据结构设计的一种排序算法。堆积是一个近似完全二叉树的结构,其实就是把数组元素想象为一颗二叉树,顺序按从上到下从左到右,但只是想象而已,并没有正真构建二叉树。这一棵想象的二叉树满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序算法描述:
将初始待排序关键字序列(R0,R1….Rn-1)构建成大顶堆,此堆为初始的无序区;
将堆顶元素R[0]与最后一个元素R[n-1]交换,此时得到新的无序区(R0,R1,……Rn-2)和新的有序区(Rn-1),且满足R[0,1…n-2]<=R[n-1];
由于交换后新的堆顶R[0]可能不再是大顶堆,因此需要对当前无序区(R0,R1,……Rn-2)调整为新的大顶堆,然后再次将R[0]与无序区最后一个元素交换,得到新的无序区(R0,R1….Rn-3)和新的有序区(Rn-2,Rn-1)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
堆排序算法的动态演示图如下:
堆排序的Java代码实现:
/**
* 堆排序的Java代码实现
*/
public class HeapSort {
public void heapSort(int[] arr) {
if (arr == null || arr.length <= 0) {
return;
}
//建立堆
headBuild(arr);
//循环遍历,交换最大值(根)到末尾
for (int i = arr.length - 1; i >= 1; i--) {
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
//交换后重新调整根为最大堆
maxHead(arr, 0, i);
}
}
/**
* 建立堆
*
* @param arr
*/
private void headBuild(int[] arr) {
//这里(arr.length >> 1) - 1是二叉树的倒数第一个非叶子节点(可以用数学推导)
//其中叶子节点不需要构建大顶堆,所以从倒数第一个非叶子节点往上遍历调整大顶堆即可
for (int i = (arr.length >> 1) - 1; i >= 0; i--) {
//构建大顶堆
maxHead(arr, i, arr.length);
}
}
/**
* 构建大顶堆
*
* @param arr
* @param index
* @param length
*/
private void maxHead(int[] arr, int index, int length) {
//根子节点index的左子节点是(index << 1) + 1,右子节点是(index << 1) + 2(可以用数学推导)
int l = (index << 1) + 1;
int r = (index << 1) + 2;
int largest = index;
if (l < length && arr[l] > arr[largest]) {
largest = l;
}
if (r < length && arr[r] > arr[largest]) {
largest = r;
}
//若最大值不在根节点,则交换最大值到根节点
if (largest != index) {
int temp = arr[largest];
arr[largest] = arr[index];
arr[index] = temp;
//递归把更改过的子节点调整为最大堆
maxHead(arr, largest, length);
}
}
}
/**
* 测试算法
*/
public class Main {
public static void main(String[] args) {
HeapSort hs = new HeapSort();
int[] arr = {34, 1, 43, 2, 67, 55, 121, 2, 34, 23, 45, 11, 10, 88, 90};
hs.heapSort(arr);
for (int i = 0; i < arr.length; i++) {
if (i != arr.length - 1) {
System.out.print(arr[i] + ",");
} else {
System.out.println(arr[i]);
}
}
}
}
代码运行结果: