1. 程式人生 > >排序演算法(3)—優先佇列,堆排序

排序演算法(3)—優先佇列,堆排序

本文主要討論基於二叉堆資料結構的優先佇列的實現以及衍生的堆排序
實現優先佇列還可以使用棧,佇列等資料結構,在此略
文章最後附有堆排序完整程式碼

優先佇列

1. 主要解決問題

有時候比不需要元素全部有序,操作時,我們可能只需要處理最大(最小)的元素
二叉堆的優先佇列主要是高效(對數級別)實現刪除最大元素,和插入元素操作。

對於其他資料結構的優先佇列的實現:佇列(刪除最古老元素)以及棧(刪除最新元素)類似

2. 二叉堆的概念

 1).當二叉樹的每個節點都小於它的父結點,則稱為堆有序。
 2).二叉堆中,位置為k的結點,父結點為不大於k/2的整數,子結點為2k和2k+1
 3).一顆大小為N的二叉樹的高度不大於lgN的整數。

3. 二叉堆的兩個重要操作

1).由上至下的堆有序化(上浮)
堆的有序狀態因為某個結點變得比他的父結點更大,而打破有序狀態,則需要交換它與它的父結點來重新實現有序堆。

    private void swim(int k)
    {
        while(k>1 && less(k/2,k))
        {
            exch(k/2,k); //交換arr[k/2]和arr[k]元素位置
            k = k/2;     //第一次比較交換後,後面的結點仍要交換
        }
    }

2).由下至上的堆有序化(下沉)


堆的有序狀態因為某個結點比它的子結點更小而打破,則需要交換它與它的子結點中較大來實現有序堆。

    private void sink(int k)
    {
        while(2*k<=N)
        {
            int j = 2*k;
            if(j<N && less(j,j+1))
                j++;
            if(!less(k,j))
                break;
            exch(k,j);
            k = j;
        }
    }

4. 基於二叉堆的優先佇列實現

1).插入元素
將新元素新增到陣列末尾,增加堆的大小,並讓這個新元素上浮到合適位置。

    public void insert(T v)
    {
        arr[++N] = v;
        swim(N);
    }

2).刪除最大元素
從陣列的頂端刪除最大元素,並將,並且將堆中最後一個元素放到頂端(此時有序堆被打破),減小堆大小,並讓這個元素下沉到合適位置。

    public T delMax()
    {
        T del = arr[1];
        exch(1,N--);
        arr[N+1] = null; //防止物件遊離
        sink(1);
        return del;
    }

複雜度
對於一個含有N個元素的堆優先佇列,插入元素不超過(lgN+1)次比較
刪除元素的操作不超過2lgN次比較

5. 堆排序

    **1).思想:**
 將原始陣列重新組織放進堆中,在下沉排序階段,按遞減順序一次取得元素並得到排序結果
 **2).實現:**
    public static void HeapSort(Comparable[] arr)
    {
        int N = arr.length;
        for(int k = N/2; k>=1; k--)
            sink(arr,k,N);
        while(N>1)
        {
            Hexch(arr,1,N--);
            sink(arr,1,N);
        }
    }

3).複雜度:
時間複雜度:NlogN
空間複雜度:1
4).堆排序特點:
目前所知的唯一同時最優利用時間和空間的排序方法—最壞的情況下也能保證使用~NlgN次比較的額外空間。
所以堆排序適用於空間十分緊張的時候(嵌入式系統等)。
堆排序完整程式碼:

package sort;
/**
  * @author : luoz
  * @date time:2016年9月4日 上午12:10:48 
**/
public class HeapSort {

    //陣列索引從零開始,而二叉樹從1開始,所以傳入引數-1,下同.
    private static boolean Hless(Comparable[] a,int i,int j)
    {
        return a[i-1].compareTo(a[j-1])<0;
    }

    private static void Hexch(Comparable[] a,int i,int j)
    {
        Comparable t = a[i-1];
        a[i-1] = a[j-1];
        a[j-1] = t;
    }

    //sink()以a[],N作為引數,其他不變.
    private static void sink(Comparable[] a,int k,int N)
    {
        while(2*k <= N)
        {
            int j = 2*k;
            if(j<N && Hless(a,j,j+1)) 
                j++;
            if(!Hless(a,k,j))
                break;          
            Hexch(a,k,j);
            k = j;
        }
    }
    /**
     * 傳入陣列arr,N為陣列長度.  
     * @param arr
     */
    public static void heapSort(Comparable[] arr)
    {
        int N = arr.length;
        for(int k = N/2; k>=1; k--)
            sink(arr,k,N);
        while(N>1)
        {
            Hexch(arr,1,N--);
            sink(arr,1,N);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Comparable[] HeapArray = {"A","C","E","D","K","Z"};     
        heapSort(HeapArray);        
        for(Comparable a : HeapArray)
            System.out.println(a);      
    }

}

演算法第四版

內容原創,轉載註明出處