數據結構——堆排序

數據結構——堆排序

排序方法很多,各有優勢,我們常用的排序方法是屬於內部排序的,對輔助空間的使用很少,而時間複雜度可能遇到了限制了,我所知道幾種排序方法最快也沒有突破nlogn 這個限制。對於平均時間複雜度來說,快速排序已經是這種算法的佼佼者了,但是它的最壞情況恐怕是不能接受的,n2 ;這裏推薦一種稍微複雜的排序,叫做堆排序,它基於一種數據結構——堆。纔有了很小的時間複雜度,同時又有很穩定的特性。

先介紹一下堆的定義:

​ 一顆二叉樹,任意非葉子節點的左右子節點都同時比它大,或者同時比它小。

表現在數組中是這樣的:

​ 一串n個元素的序列,a1,a2,...,an ,下標由1開始;

{kik2ikik2i+1

{kik2ikik2i+1

(i=1,2,...,n/2.)

堆的定義有很明顯的作用,最小的或者最大的數字永遠在堆頂,對嗎?這樣子每次能夠從堆頂拿出一個數字,並且從堆裏面刪去這個數字,再拿,如此往復,組成一個序列不就是一個有序的數組嗎?並且用時是n 。很美好。但是維護一個堆刪除了堆頂的數字依然有序這是需要代價的,你需要調整幾乎一個堆,從上至下。讓數字的位置又滿足堆的定義。

重新調整堆的方法叫做“篩選”,是這樣的:

假設一個標準的堆,拿出了堆頂的元素,要刪除堆頂的元素;這裏寫圖片描述

拿出13 ,把97放到堆頂,這裏寫圖片描述
97破壞了以1節點下的堆,所以交換1節點和它的子節點,選擇2,3節點中小的那一個交換,那就是27這個3節點,這樣子1節點下的堆就維護好了,但是破壞了3節點下的堆。所以依法炮製,換3節點和它的子節點。直到沒得換了。這裏寫圖片描述

接下來再拿出堆頂元素,27.並且維護下堆,如上方法:這裏寫圖片描述

還有個問題沒解決的,就是初始的時候建立一個堆。

很簡單的一棵樹由下往上,可以生成堆的節點,也就是有子節點的節點就“篩選”一下就可以形成堆。imgimgimgimgimg

這個圖片是借用一下別人的,所以數字不同於上面的了,但是是一個思路,在這隻做演示使用。(畫圖有點累啊)!!

很詳細了。按圖索驥都成了,所以貼代碼了。

#include<cstring>
#include<cstdio>

using namespace std;

void HeapAdjust(int a[],int s,int e)
{
    int length = e-s;
    int rc=a[s];
    for(int i=2*s;i<=e;i*=2)
    {
        if(i<e &&a[i]<a[i+1])
            i++;
        if(a[i]<rc)
            break;
        a[s] = a[i];
        s=i;
    }
    a[s] = rc;
}

void HeapSort(int a[],int length)          //a數組必須由下標1開始儲存
{
    for(int i=length/2;i>0;i--)
    {
        HeapAdjust(a,i,length);
    }
    int t;
    for(int i=length;i>1;i--)
    {
        t=a[i];
        a[i]=a[1];
        a[1]=t;
        HeapAdjust(a,1,i-1);
    }
}
int main()
{
    int a[10]={0,49,38,65,97,76,13,27,49};
    HeapSort(a,8);
    for(int i=1;i<=8;i++)
        printf("%d ",a[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章