1. 程式人生 > >《演算法(第四版)》排序-----堆排序

《演算法(第四版)》排序-----堆排序

1.什麼是堆?

講堆排序之前,先了解一下什麼是堆。堆其實相當於一種資料結構,它的本質是一種陣列物件,但是它裡面的內同又是一顆完全二叉樹結構,它的特點是父節點的值大於(或小於)兩個子節點的值,常常用於優先佇列、堆排序等。

堆在陣列中的索引有如下的特點。陣列索引為k的元素,它的父節點的索引為[k/2](下取整),它的兩個子節點索引為2k, 2k+1,依次類推

2.堆排序的基本過程

(1)構造一個堆

如果給定一個數組,只需要從左到右遍歷陣列,用swim()保證掃描指標左側的所有元素已經是一顆堆有序的完全二叉樹即可,就像連續向優先佇列中插入元素一樣,但是更有效的辦法是由又想做用sink()下浮的方式來構造堆。

(2)基本思想

用白話來講,堆排序是很簡單的,你先用下沉的方法構造了一個堆後,堆有一個特點啊,那就是它的第一個元素永遠是最大(或最小)的,如果你想從小到大排,那就把首元素和最後一個元素交換,肯定沒毛病,這樣最大的就歸位了。下一步再把前n-1個元素利用下沉恢復堆的結構,這樣倒數第二大的有跑到最前面了,那就讓它再和倒數第二個交換就行了,依次類推。。。。

參照《演算法第四版》圖解


(3)具體程式碼實現:

public static void  heapSort(Comparable[] a){
    int N = a.length;
    for(int k = N/2; k >= 1; k--){//利用下沉將堆
        sink(a, k, N);
    }
    while(N>1){
        exch(a, 1, N--);//將最前面的和後面交換,此處注意N--了,所以下一行的N已經是N--後的值了
        sink(a, 1,N);   //利用下沉恢復堆有序
    }
}

//觀察可以發現,此處的sink不是之前的部落格講的只傳入int  k  讓某個元素下沉就好,此處傳入了a[]  ,N,因為這個N是變化的,不斷的在減小
public static void sink(Comparable[] a, int i, int j){
    while( 2*i < j){
        int k = 2 * i;
        if(k < j && less(k, k+1))   k++;
        if(less(k, i))  break;
        exch(a, i, k);
        i = k;
    }
}
(4)說明

堆排序在現代系統的許多應用很少用到它,因為它無法利用快取,但是用堆實現的優先佇列在現在應用中越來越重要,因為它能插入操作和刪除最大元素混合動態場景中保證對級數級別的執行時間,尤其是資料量較大時用,比如10億個元素中,選出最大的10個等。