堆排序 圖解排序算法(三)之堆排序

 

 

package sort;

import java.util.Arrays;

public class HeapSort {
    public static void main(String[] args) {
        int[] array = new int[]{2, 1, 4, 3, 6, 5, 8, 7};
        // 接下來就是排序的主體邏輯
        sort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void sort(int[] array) {
        // 按照徹底二叉樹的特色,從最後一個非葉子節點開始,對於整棵樹進行大根堆的調整
        // 也就是說,是按照自下而上,每一層都是自右向左來進行調整的
        // 注意,這裏元素的索引是從0開始的
        // 另外一件須要注意的事情,這裏的建堆,是用堆調整的方式來作的
        // 堆調整的邏輯在建堆和後續排序過程當中複用的
        for (int i = array.length / 2 - 1; i >= 0; i--) {
            adjustHeap(array, i, array.length);
        }

        // 上述邏輯,建堆結束
        // 下面,開始排序邏輯
        for (int j = array.length - 1; j > 0; j--) {
            // 元素交換
            // 說是交換,其實質就是把大頂堆的根元素,放到數組的最後;換句話說,就是每一次的堆調整以後,都會有一個元素到達本身的最終位置
            swap(array, 0, j);
            // 元素交換以後,毫無疑問,最後一個元素無需再考慮排序問題了。
            // 接下來咱們須要排序的,就是已經去掉了部分元素的堆了,這也是爲何此方法放在循環裏的緣由
            // 而這裏,實質上是自上而下,自左向右進行調整的
            adjustHeap(array, 0, j);
        }
    }

    /**
     * 這裏,是整個堆排序最關鍵的地方,正是由於把這個方法抽取出來,才更好理解了堆排序的精髓,會盡量仔細講解
     *
     * @param array
     * @param i
     * @param length
     */
    public static void adjustHeap(int[] array, int i, int length) {
        // 先把當前元素取出來,由於當前元素可能要一直移動
        int temp = array[i];
        // 能夠參照sort中的調用邏輯,在堆建成,且完成第一次交換以後,實質上i=0;也就是說,是從根所在的最小子樹開始調整的
        // 接下來的講解,都是按照i的初始值爲0來說述的
        // 這一段很好理解,若是i=0;則k=1;k+1=2
        // 實質上,就是根節點和其左右子節點記性比較,讓k指向這個不超過三個節點的子樹中最大的值
        // 這裏,必需要說下爲何k值是跳躍性的。
        // 首先,舉個例子,若是a[0] > a[1]&&a[0]>a[2],說明0,1,2這棵樹不須要調整,那麼,下一步該到哪一個節點了呢?確定是a[1]所在的子樹了,
        // 也就是說,是以本節點的左子節點爲根的那棵小的子樹
        // 而若是a[0}<a[2]呢,那就調整a[0]和a[2]的位置,而後繼續調整以a[2]爲根節點的那棵子樹,並且確定是從左子樹開始調整的
        // 因此,這裏面的用意就在於,自上而下,自左向右一點點調整整棵樹的部分,直到每一顆小子樹都知足大根堆的規律爲止
        for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
            System.out.println("k==========="+k);
            // 讓k先指向子節點中最大的節點
            if (k + 1 < length && array[k] < array[k + 1]) {
                k++;
            }

            // 若是發現子節點更大,則進行值的交換
            if (array[k] > temp) {
                swap(array, i, k);
                // 下面就是很是關鍵的一步了
                // 若是子節點更換了,那麼,以子節點爲根的子樹會不會受到影響呢?
                // 因此,循環對子節點所在的樹繼續進行判斷
                i = k;
                // 若是不用交換,那麼,就直接終止循環了
            } else {
                break;
            }
        }
    }

    /**
     * 交換元素
     *
     * @param arr
     * @param a   元素的下標
     * @param b   元素的下標
     */
    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

  

 

參考 html

圖解排序算法(三)之堆排序   http://www.javashuo.com/article/p-wtyhbkog-dg.htmljava

相關文章
相關標籤/搜索