堆排序:学习记录

堆排序

核心要点:

  • 通过下沉的方式,自底向上进行建堆 ,可以保证当检测到有父节点的堆有序时,其所有子堆都是满足堆的成立条件。即父节点大于任意两个子节点
  • 下沉排序的过程,实质上是在删除最大元素后,堆的自我调整过程。调整的过程中,堆逐渐构成一个有序序列
  • 父节点的座标是左子节点的一半,所以开头要减一。
  • 由于使用了一个完全二叉树,因此索引为0的位置不能有数
public static void heapSort(int[] arr) {
    int N = arr.length - 1;
    // 建堆的模式是自下而上进行的,完全二叉树的性质,数组从1开始记录
    for (int i = N / 2; i >= 1; i--) {
        // 下沉建堆。保证父节点比两个子节点大
        sink(arr, i, N);
    }
    while (N > 1) {
        // 将最大的值交换到最后面(删除最大元素),并且数组长度减一。这样下去可以得到最终有序的数组
        swap(arr, 1, N--);
        // 原堆被打破,从子节点选择一个最大的替换堆顶。对交换后的堆进行下沉再排序
        sink(arr, 1, N);
    }
}

private static void sink(int[] arr, int a, int N) {
    // 需要从上至下进行遍历
    while (2 * a <= N) {
        // 子节点座标
        int j = a * 2;
        // 右子节点比左子节点大,选择右子节点, 并且座标要保证不超过N
        if (j < N && arr[j + 1] > arr[j]) j++;
        // 如果父堆比子堆大,则不需要下沉。因为默认是从下自上建堆的
        if (arr[a] > arr[j]) break;
        // arr[a] < arr[j] 交换a和j的位置,因为j的序号较大,需要将较大值放到后面
        swap(arr, a, j);
        // 继续遍历子节点
        a = j;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章