排序算法-----堆排序

public class HeapSort {
    /**
     * 初始化
     * 根据数组建立一个堆,此处为大顶堆,大顶堆的每个节点的值都大于其左右孩子的值
     * @param arr
     */
    public static void buildHeap(int[] arr) {
        int len = arr.length;
        int lastNode = len/2;//最后一个节点
        for(int i=lastNode;i>=1;i--) {
             // 对所有的非叶子节点进行循环 ,且从最后一个非叶子节点开始
            heapAdjust(arr, i, len);
        }
    }
    /**
     * 对堆进行调整
     * @param arr
     * @param parentNodeIndex 非叶子节点的index
     * @param len
     */
    public static void heapAdjust(int[] arr,int parentNodeIndex,int len) {
        int maxNodeIndex = parentNodeIndex;
         // 如果有左子树,i * 2为左子树节点索引
        // i 节点和叶子节点的关系为 2*i 和 2*i+1 根节点的i为1 , 索引值需要减去1
        if(parentNodeIndex*2<=len) {
            // 如果父节点小于左子树时
            if ((arr[parentNodeIndex - 1]-(arr[parentNodeIndex * 2 - 1])) < 0) {
                maxNodeIndex = parentNodeIndex * 2;// 记录最大索引为左子节点索引
            }
            // 只有在有左子树的前提下才可能有右子树,再进一步断判是否有右子树
            if (parentNodeIndex * 2 + 1 <= len) {
                // 如果右子树比最大节点更大
                if ((arr[maxNodeIndex - 1]-(arr[(parentNodeIndex * 2 + 1) - 1])) < 0) {
                    maxNodeIndex = parentNodeIndex * 2 + 1;// 记录最大索引为右子节点索引
                }
            }
        }
         // 如果在父节点、左、右子节点三者中,最大节点不是父节点时需要交换,把最大的与父节点交换,创建大顶堆
        if (maxNodeIndex != parentNodeIndex) {
            swap(arr, parentNodeIndex - 1, maxNodeIndex - 1);
            // 交换后可能需要重建堆,原父节点可能需要继续下沉  因为交换后 maxNodeIndex位置的值就不一定是三个节点中最大的了!
            //向下递归怎么保证最大值到根结点,因为初始化之后元素有序??除根结点外,左右是次大值
            if (maxNodeIndex * 2 <= len) {// 是否有子节点,注,只需判断是否有左子树即可知道
                heapAdjust(arr, maxNodeIndex, len);
            }
        }

    }
    public static void swap(int[] arr,int i,int j) {
        if (i != j) {// 只有不是同一位置时才需交换
            int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
    }

    public static void heapSort(int[] arr) {
        //初始化一个大顶堆
        buildHeap(arr);
        /*for (int i : arr) {
            System.out.print(i+"  ");

        }*/
         /*
         * 对初始堆进行循环,且从最后一个节点开始,直到树只有两个节点止 每轮循环后丢弃最后一个叶子节点,再看作一个新的树
         */
        for (int i = arr.length; i >= 2; i--) {
            // 根节点与最后一个叶子节点交换位置,即数组中的第一个元素与最后一个元素互换
            swap(arr, 0, i - 1);
            // 交换后需要重新调整堆,堆的末尾少1,即不计入结果
            heapAdjust(arr, 1, i - 1);//递归重新的构建一个大顶堆
        }
    }


    public static void main(String[] args) {

        int[] arr = {6, 9, 0, 4, 5, 9, 1, 4, 2, 6, 3, 8, 0, 7, 0, -7, -1, 34};
        heapSort(arr);
        for (int i : arr) {
            System.out.println(i);

        }
        System.out.println("--------------------");
        int[] arr2 = new int[]{49, 38, 65, 97, 76, 13, 27, 48, 55, 4};
        heapSort(arr2);
        for (int i : arr2) {
            System.out.println(i);

        }

    }

}

猜你喜欢

转载自blog.csdn.net/weixin_42061676/article/details/81093074