java 堆排序 最簡潔實現版

堆排序整體思路:

 1. 初始化最大堆
 2. push堆頂元素倒最後,並將堆長度減一,直到堆長度爲0

首先幾個關於堆的知識:

  1. 堆就是完全二叉樹,  最大堆的特性: 任意的父節點總比其兩個子節點大.

  2. 堆排序原理:

  1. 先將數組整理成一個最大堆. (最大堆就是升序排列,最小堆就是降序排列,)
  2. 開始push堆頂元素,將最後一個元素放入堆頂,並重新向下整理堆,直到堆長度爲0 (數組中實現就是第一個元素和最後一個元素交換位置)
  3. 整理一遍堆的時間複雜度是 O(logn), 第一次整理了n/2次,之後每次push操作又整理了n-1次. 故整體時間複雜度約爲 O(n*logn)

  3.二叉樹的節點轉換公式:  如果有節點下標爲n,則其左子節點下標爲 2n,右子節點下標爲2n+1,父節點下標爲 n/2

Java具體實現:

package arithmetic.sort;

import java.util.Arrays;

/**
 * 堆排序 簡潔優雅版
 * @author jiangfeng 2019/7/29 12:45
 */
public class HeapSort2 {

    public static void main(String[] args) {
        int[] a = {24, 10, 5, 1, 2, 24, 5, 1, 2, 5, 7, 8, 5, 3, 7, 63, 9, 0, 42, 3, 8, 24, 1};
        //int [] a =  { 5, 4, 3, 2, 1 };
        long start = System.currentTimeMillis();
        heapSort(a);
        System.out.println(Arrays.toString(a)); // 1ms
        //System.out.println(JsonOutput.toJson(a));//gson裏的 json output轉換那個很慢. 41ms
        //System.out.println(JSON.toJSONString(a));//序列化更慢了 163ms
        System.out.println("用時:" + (System.currentTimeMillis() - start));
    }

    private static void heapSort(int[] a) {
        // 1.初始化最大堆,從倒數第二層開始初始化
        for (int i = a.length/2; i >=0; i--) {
            sortDownHeap(a,a.length,i);
        }
        // 2. push堆頂元素倒最後,並且重新建立最大堆
        for (int i = a.length-1; i >=0 ; i--) {
            swap(a,0,i);
            sortDownHeap(a,i-1,0);
        }
    }

    /**
     * 最大堆向下調整
     * @param a
     * @param length 堆的大小,邊界
     * @param i  需要調整順序的元素
     */
    private static void sortDownHeap(int[] a, int length, int i) {
        //  最大堆的特性: 任意的父節點總比其兩個子節點大.
        //  二叉樹節點轉換: 如果有節點下標爲n,則其左子節點下標爲 2n,右子節點下標爲2n+1,父節點下標爲 n/2
        int t = i+1; //便於理解 數組的下標序號和數組的序號的轉換.  下文也需注意這點: 數組實際下標 = 堆下標 - 1;
        while (2*t <= length) { // 該節點不是最後一層,存在左子節點
            int tmpMax = t;// 記錄父子節點中的最大下標
            if (a[t - 1] < a[2 * t - 1]) { // 父節點和左子節點比較出最大值
                tmpMax = 2 * t;
            }
            if (a[tmpMax - 1] < a[2 * t]) { // 上次比較中較大的和右子節點比較
                tmpMax = 2 * t + 1;
            }
            if (tmpMax != t) {  // 如果當前根節點不是最大值,則執行交換.
                swap(a, t - 1, tmpMax - 1);
                t = tmpMax;// 繼續向下調整
            } else {
                return;// 否則停止調整
            }
        }
    }

    private static void swap(int[] a, int i, int j) {
        int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章