堆排序

堆排序
先了解一些性质:1、complate binary tree,2、父节点的值大于其左、右孩子节点的值
堆排序是基于完全二叉树实现的,在将一个数组调整成一个堆的时候,关键之一的是确定最后一个非叶子节点的序号,这个序号为:n/2-1,n为数组的长度。但是为什么呢?
可以分两种情形考虑:

  • 堆的最后一个非叶子节点若只有左孩子
  • 堆的最后一个非叶子节点有左右两个孩子,完全二叉树不可能只有右孩子,而没有左孩子
    完全二叉树的性质之一是:如果节点序号为i,在它的左孩子序号为:2i+1,右孩子序号为:2i+2。

package org.study.order;

import java.util.Arrays;

public class HeapSort {

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

    public static void sort(int[] arr) {
        //先原地建最大堆
        int heapSize = arr.length;
        for (int i = (heapSize >> 1) - 1; i >= 0; i -- ) { //(heapSize >> 1) - 1:最后一个非叶子节点的索引
            siftDown(arr, i, arr.length); //自下而上的下虑
        }

        while (heapSize > 1) {
            swap(arr, 0, heapSize - 1); //0 堆顶部元素、heapSize-1 堆的尾部元素
            heapSize --; //取出最大的元素
            siftDown(arr, 0, heapSize); //恢复最大堆的性质
        }

    }

   public static void siftDown(int[] arr, int parent, int length) {
        //先保存即将下沉节点的值
        int element = arr[parent];
        int child = 2 * parent + 1; //先拿到左子节点,默认左子节点比较大

        while (child < length) {

            //存在右子节点,并且右子节点比较大
            int rightChild = child + 1;
            if (rightChild < length && arr[child] < arr[rightChild]) {
                child = rightChild;
            }

            //如果比自己诶但都大,就退出
            if (element > arr[child]) {
                break;
            }

            //如果比子节点小就要将子节点的值上移
            arr[parent] = arr[child];
            parent = child;
            child = 2 * child + 1; //先算出下移后的父节点的左孩子节点的索引
        }

        arr[parent] = element;
    }

    public static void swap(int[] arr, int a, int b) {
        int tmp = arr[a];
        arr[a] = arr[b];
        arr[b] = tmp;
    }

}

posted @ 2021-03-06 20:58  Leo-Wong  阅读(57)  评论(0编辑  收藏  举报