1、首先了解堆是什么
2、堆的性质
这里我们用到两种堆,其实也算是一种。
最大树:每个节点的值都大于或者等于它的左右子节点的值。
最小树:每个节点的值都小于或者等于它的左右子节点的值。
如上所示,就是两种堆。
如果我们把这种逻辑结构映射到数组中,就是下边这样

这个数组arr逻辑上就是一个堆。
从这里我们可以得出以下性质(重点)
len 当前数组的总长
1.父结点索引:第一个父节点索引地址 i = len/2-1(这里计算机中的除以2,省略掉小数) 例如 父节点3,它的左节点是7,右节点8
2.左孩子索引:2i+1
3.右孩子索引:2i+2
所以上面两个数组可以脑补成堆结构,因为他们满足堆的定义性质:
对于大根堆:arr(i)>arr(2i+1) && arr(i)>arr(2i+2)
对于小根堆:arr(i)<arr(2i+1) && arr(i)<arr(2i+2)
3、堆排序的基本思想
了解了以上内容,我们可以开始探究堆排序的基本思想了。
堆排序的基本思想是:
1、将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;2、将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;
3、重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了。
升序用大根堆,降序就用小根堆
演示网址:
https://www.cs.usfca.edu/~galles/visualization/HeapSort.html
4、代码演示
升序:
public class 堆排序 {/*i 当前数组的总长1.父结点索引:第一个父节点 i = len/2-1(这里计算机中的除以2,省略掉小数) 例如 父节点3,它的左节点是7,右节点82.左孩子索引:2*i+13.右孩子索引:2*i+2所以上面两个数组可以脑补成堆结构,因为他们满足堆的定义性质:大根堆:arr(i)>arr(2*i+1) && arr(i)>arr(2*i+2)小根堆:arr(i)<arr(2*i+1) && arr(i)<arr(2*i+2)*/public static void main(String[] args) {int[] ints = {155, 55, 44, 56, 76, 13, 18, 55};int[] ints1 = HeapSort(ints);System.out.println(Arrays.toString(ints1));}public static int[] HeapSort(int[] array) {if (array.length < 1) {return array;}int len = array.length;// 构建最大堆buildMaxHeap(array, len);// 循环交换最大堆的顶点和最后一位数的位置while (len > 0) {// 交换位置,因为此时的最大堆的顶点就是最大值swap(array, 0, len - 1);// len减一是,最后一位已经是最大值了,不需要在考虑了len--;// 重新调整最大堆heapify(array, 0, len);}return array;}// 构建大根堆private static void buildMaxHeap(int[] array, int len) {// (len - 1) / 2 父节点索引算法,循环构建最大树int maxTree = len / 2 - 1;for (int i = maxTree; i >= 0; i--) {System.out.println("i = " + i);// 找到父节点,进行比较判断是否换位heapify(array, i, len);}}// 调整成为最大堆 i 头节点的下标private static void heapify(int[] array, int i, int len) {// 记录父节点的值的指针int max = i;// 计算出父节点的左节点int left = 2 * i + 1;// 计算出父节点的右节点int right = 2 * i + 2;// 如果有左子树len > left,且左子树大于父节点,则将最大指针指向左子树if (len > left && array[left] > array[max]) {max = left;}//如果有右子树len > right,且右子树大于父节点,则将最大指针指向右子树if (len > right && array[right] > array[max]) {max = right;}// 说明父节点不是最大的,此时进行交换位置if (max != i) {swap(array, max, i);// 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整heapify(array, max, len);}}/*** 交换索引** @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;}}
