初級排序算法之堆排序

堆排序的思想

堆排序的具體算法,思想是每次取出堆的最頂層根節點,即數組下標爲0,然後與最後一個節點即i+1交換。
參考地址

建堆過程:

  1. 首先將原始隊列構建成完全二叉樹
  2. 然後從第一個非葉子節點開始,比較當前節點和其孩子節點,將最大的元素放在當前節點,交換當前節點和最大節點元素。
    注意:如果根節點是a[0],那麼第一個非葉子節點就是倒數第二層的最後一個根節點,下標爲length/2-1
  3. 將當前元素前面所有的元素都進行2的過程,這樣就生成了最大堆
   /**
     * @param data 原始數組序列
     * @brief 構建堆
     */
    public static void buildHeap(int[] data) {
        /**
         * 獲取最後一個非葉子節點
         */
        int begin = data.length / 2;
        for (int i = begin; i >= 0; i--) {
            adjustHeap(data, data.length, i);
        }
    }

    /**
     * @param data     要調整的數組
     * @param heapSize 長度
     * @param index    需要調整的節點的下標
     * @brief 調整堆
     */
    public static void adjustHeap(int[] data, int heapSize, int index) {

        /**
         * 節點index的左孩子下標
         */
        int leftChildSubscript = 2 * index + 1;
        /**
         *節點index的右孩子下標
         */
        int rightChildSubscript = 2 * index + 2;

        /**
         * 最大元素的初始下標
         */
        int largestSubscript = index;
        /**
         * 找到最大元素
         */
        /**
         * 如果當前根節點小於左孩子的值,那麼最大元素的下標爲左孩子的下標.
         */
        if ((leftChildSubscript < heapSize) && (data[largestSubscript] < data[leftChildSubscript])) {
            largestSubscript = leftChildSubscript;
        }
        /**
         *如果當前根節點小於右孩子的值,那麼最大元素的下標爲右孩子的下標.
         */
        if ((rightChildSubscript < heapSize) && (data[largestSubscript] < data[rightChildSubscript])) {
            largestSubscript = rightChildSubscript;
        }

        /**
         * 將最大元素調整至根節點.
         * 根節點不是最大的,那麼就調整.
         */
        if (index != largestSubscript) {
            /**
             * 將根節點的值與子節點中的最大值進行調整.
             */
            swapElements(data, index, largestSubscript);
            /**
             */
            adjustHeap(data, heapSize, largestSubscript);
        }
    }

    public static void swapElements(int[] data, int index1, int index2) {
        int temp = data[index1];
        data[index1] = data[index2];
        data[index2] = temp;
    }

堆排序的過程:
首先將原始序列構建爲一個堆。

  1. 將堆頂元素和最後一個元素交換,列表長度減1。由此無序區減1,有序區加1
  2. 剩餘元素重新調整建堆
  3. 繼續1和2,直到所有元素都完成排序
    /**
     * @param data 原始數組
     * @brief 堆排序
     */
    public static void heapSort(int[] data) {
        int length = data.length;
        /**
         * 構建堆
         */
        buildHeap(data);
        while (length >= 1) {
            /**
             * 將堆的最後一個元素與堆頂元素交換.
             */
            swapElements(data, 0, length - 1);

            length--;
            /**
             * 將剩餘元素調整爲堆
             */
            adjustHeap(data, length, 0);
        }
    }

時間複雜度分析

建堆的時間複雜度最差爲O(N) ,最好爲O(1)

堆排序的時間複雜度是O(NlogN)

堆排序爲原地排序,空間複雜度爲O(1)

結果

發佈了266 篇原創文章 · 獲贊 9 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章