算法其实很简单 — 堆排序

目录

1. 基本概念篇

1.1 堆排序

1.2大顶堆和小顶堆

2. 基本思路与步骤

2.1如何构建大顶堆

2.2 排序过程

3. 代码实现


1. 基本概念篇

1.1 堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。

1.2大顶堆和小顶堆

  • 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  • 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

 

备注:图片来源https://www.cnblogs.com/chengxiao/p/6129630.html

2. 基本思路与步骤

  1. 将无序的数组构建成大顶堆(一般升序用大顶堆,降序用小顶堆)
  2. 将大顶堆的首尾互换,重新构建大顶堆,以此循环。如:第一轮,首位为最大值,互换以后,最大值排在最后一位,再将整体数组的长度-1,重新构建大顶堆,如此反复。

2.1 如何构建大顶堆

  1. 找到所有非叶子节点坐标,非叶子节点顺序为自下而上,从右到左。即:数组length/2-1~0
  2. 将非叶子节点,自上而下,从右到左进行互换,最终生成大顶堆。即:当前节点i*2+1为左子节点,i*2+2为右子节点。先将左子节点和右子节点比较,将较大子节点的value和当前节点的value进行互换

注意:每次交换的节点为自下而上、从右到左,但是交换的过程是从该节点自上而下、从右到左。

动态效果可进入网址进行演示:https://visualgo.net/zh/heap,左下角--创建--输入数组--创建,即可查看动态效果

2.2 排序过程

过程不在描述,具体可进入网址,https://visualgo.net/zh/heap,点击堆排序即可查看动态效果。

3. 代码实现

基本每行代码都有注释

/**
 * 堆排序
 * 动态效果:https://visualgo.net/zh/heap
 *
 * @author 浪子傑
 * @version 1.0
 * @date 2020/5/27
 */
public class SortHeapSort {

    public static void main(String[] args) {
        int[] arr = {4, 6, 8, 9, 5};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 堆排序
     *
     * @param arr
     */
    public static void sort(int[] arr) {
        // 将非叶子节点和左右节点自下而上、自右向左循环构建大顶堆
        // arr.length/2 -1为第一个非叶子节点
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);

        }
        // 将root节点和最后一个节点交换后,自上而下、自右向左构建为大顶堆
        for (int i = arr.length - 1; i > 0; i--) {
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            adjustHeap(arr, 0, i);
        }
    }

    /**
     * 重点:将以i为节点,自上而下、自右向左构建为大顶堆
     *
     * @param arr
     * @param i      非子节点
     * @param length
     */
    public static void adjustHeap(int[] arr, int i, int length) {
        // 获取到当前i的value
        int temp = arr[i];
        // i * 2 + 1为当前节点的左子节点
        for (int j = i * 2 + 1; j < length; j = j * 2 + 1) {
            // 如果左子节点小于右子节点,则让j指向右子节点
            if (j + 1 < length && arr[j] < arr[j + 1]) {
                j++;
            }
            // 如果当前子节点的value > 当前节点的value,则交换值
            if (arr[j] > temp) {
                arr[i] = arr[j];
                arr[j] = temp;
                // 为下次循环做准备
                i = j;
            } else {
                break;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/guozhangjie1992/article/details/106394434