private void buildHeap(int[] h) {
        int l = h.length;
        //这里需要从下向上调整,因为从上向下调整只能让最小值下到底端,只有从下向上调整可以让最大值上到顶端
        //shiftDown需要递归,如果不递归,这里只能保证最大的元素在堆顶,但是不能保证子分支都是最大堆
        //这里下标 l/2 -1  是倒数第二层中从左到右最后一个非叶子节点(倒数第二层中最后一个含有子节点的节点)的数组下标
        for (int i = (l / 2 - 1) ; i >= 0; i--) {
            shiftDown(h, i);
        }
    }
    private void shiftDown(int[] h, int i) {
        int l = h.length;
        //右子节点的数组下标大于 数组最后一个元素下标,没有右子节点
        if (2 * i + 2 > l - 1) {  
            //左子节点的数组下标大于数组最后一个元素的下标
            if (2 * i + 1 > l - 1) {
                //没有左节点,不需要交换
                return;
            } else {
                if (h[i] < h[2 * i + 1]) {
                    //交换根和左子节点
                    swap(h, i, 2 * i + 1);
                    shiftDown(h, 2 * i + 1);
                } else {
                    //如果不需要交换,下面递归也不需要,因为调整是从下向上,如果这里没有交换,那么下面的子分支没有受到影响也不需要调整
                    return;
                }
            }
        } else {
            if (h[2 * i + 1]  >  h[2 * i + 2]) {
                //左节点大与右子节点
                if (h[i] < h[2 * i + 1]) {
                    //左子节点大于根节点
                    swap(h, i, 2 * i + 1);
                    shiftDown(h, 2 * i + 1);
                } else {
                    return;
                }
            } else {
                //右节点大
                if (h[i] < h[2 * i + 2]) {
                    swap(h, i, 2 * i + 2);
                    shiftDown(h, 2 * i + 2);
                } else {
                    return;
                }
            }
        }
    }
    private void swap(int[] h, int i, int j) {
        int temp = h[i];
        h[i] = h[j];
        h[j] = temp;
    }