public class SiftUpComparable {

    /**
     * 构建最小堆代码
     * @param index 将要入队的数组的角标
     * @param value 将要入队的值
     * @param array 数组
     */
    public static void  siftUpComparable(int index,int value,Integer[] array){
        while(index>0){
            // 得到父角标位置
            int parent = (index-1)>>>1;
            // 用父节点的值和将要入队的值进行比较,如果比父节点的值小则和父节点进行交换,因为这里构建的事小顶堆,所以要比较和交换比父节点的小的
            // 如果父节点比将要插入的数据小,则直接退出
            if(value>array[parent]){
              break;
            }
            // 此时表示将要入队的节点数据比父节点的值要小,需要交换
            // 把父节点的值拿出来,赋值给将要插入的数组角标的位置
            int parentValue = array[parent];
            array[index] = parentValue;
            // 因为需要和父节点交换,因此使角标交换
            index = parent;
        }
        array[index] = value;
    }


    /**
     * 获取堆顶元素
     * @param array
     * @return
     */
    public static int siftDownComparable(Integer[] array){
        int n= array.length -1;
        // 弹出的堆顶元素 最小的
        int topValue = array[0];
        // 最小堆中最后一个元素
        int endKey = array[n];
        // 将尾节点置为null
        array[n] = null;
        if(n<=0 ){
            return 0;
        }
        // 循环次数为整个数据长度减一的一半,因为比较左节点从上到下依次比较,比较一次为一次循环,次数为 n>>>1
        int half = n>>>1;
        // 每次比较交换的的初始脚标,刚开始要从堆顶开始,也是 0,每次的值都是下一级节点中最小的那个值
        int k = 0 ;
        while(k<half){
             //获取下一级左节点的脚标,child永远指向下一级两个节点中最小的节点角标
            int child = (k<<1)+1;
            //获取下一级右节点的脚标
            int right = child+1;
            // 获取下一级左节点的值 远指向下一级两个节点中最小的节点的值
            int c = array[child];
            // 如果right大于n,则证明此时没有右节点了
            if(right<n && array[child]>array[right]){
                c = array[child=right];
            }
            // 如果尾节点的值小于子节点的值,则退出本次循环,尾节点的值是要放入首节点角标为0的位置的
            if(endKey<c){
               break;
            }
            // 如果尾节点的值大于子节点的值,则需要交换,将首节点的值替换为比其小的子节点的值
            array[k] = c;
            // 将k的值下移为child
            k = child;
        }
        // 将尾节点放入到合适的位置
        array[k] = endKey;
      return topValue;
    }




    public static void main(String[] args) {
        Integer[] array = new Integer[5];
        Random random = new Random();
        System.out.println("入队 ");
        for (int i = 0; i < 5; i++) {
            int value = random.nextInt(100);
            System.out.print(value+"  ");
            siftUpComparable(i, value, array);
        }
        print(array);
        System.out.println();
        System.out.println("出队");
        System.out.println("出队的值 = "+siftDownComparable(array));
        print(array);

    }


    public static  void print( Integer[] array){
        System.out.println();
        for (int k=0;k<array.length;k++){
            System.out.print(array[k]+"  ");
        }
    }




}