小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

堆排序

 Qin Hantang 2013-09-10

                                                 堆排序

       堆排序是利用堆的性質(zhì)進(jìn)行的一種選擇排序。下面先討論一下堆。

1.堆

  堆實(shí)際上是一棵完全二叉樹,其任何一非葉節(jié)點(diǎn)滿足性質(zhì):

  Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]

  即任何一非葉節(jié)點(diǎn)的關(guān)鍵字不大于或者不小于其左右孩子節(jié)點(diǎn)的關(guān)鍵字。

  堆分為大頂堆和小頂堆,滿足Key[i]>=Key[2i+1]&&key>=key[2i+2]稱為大頂堆,滿足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]稱為小頂堆。由上述性質(zhì)可知大頂堆的堆頂?shù)年P(guān)鍵字肯定是所有關(guān)鍵字中最大的,小頂堆的堆頂?shù)年P(guān)鍵字是所有關(guān)鍵字中最小的。

2.堆排序的思想

   利用大頂堆(小頂堆)堆頂記錄的是最大關(guān)鍵字(最小關(guān)鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。

    其基本思想為(大頂堆):

    1)將初始待排序關(guān)鍵字序列(R1,R2....Rn)構(gòu)建成大頂堆,此堆為初始的無序區(qū);

    2)將堆頂元素R[1]與最后一個元素R[n]交換,此時得到新的無序區(qū)(R1,R2,......Rn-1)和新的有序區(qū)(Rn),且滿足R[1,2...n-1]<=R[n]; 

    3)由于交換后新的堆頂R[1]可能違反堆的性質(zhì),因此需要對當(dāng)前無序區(qū)(R1,R2,......Rn-1)調(diào)整為新堆,然后再次將R[1]與無序區(qū)最后一個元素交換,得到新的無序區(qū)(R1,R2....Rn-2)和新的有序區(qū)(Rn-1,Rn)。不斷重復(fù)此過程直到有序區(qū)的元素個數(shù)為n-1,則整個排序過程完成。

    操作過程如下:

     1)初始化堆:將R[1..n]構(gòu)造為堆;

     2)將當(dāng)前無序區(qū)的堆頂元素R[1]同該區(qū)間的最后一個記錄交換,然后將新的無序區(qū)調(diào)整為新的堆。

    因此對于堆排序,最重要的兩個操作就是構(gòu)造初始堆和調(diào)整堆,其實(shí)構(gòu)造初始堆事實(shí)上也是調(diào)整堆的過程,只不過構(gòu)造初始堆是對所有的非葉節(jié)點(diǎn)都進(jìn)行調(diào)整。

    下面舉例說明:

     給定一個整形數(shù)組a[]={16,7,3,20,17,8},對其進(jìn)行堆排序。

    首先根據(jù)該數(shù)組元素構(gòu)建一個完全二叉樹,得到

 
 然后需要構(gòu)造初始堆,則從最后一個非葉節(jié)點(diǎn)開始調(diào)整,調(diào)整過程如下:

20和16交換后導(dǎo)致16不滿足堆的性質(zhì),因此需重新調(diào)整

這樣就得到了初始堆。

即每次調(diào)整都是從父節(jié)點(diǎn)、左孩子節(jié)點(diǎn)、右孩子節(jié)點(diǎn)三者中選擇最大者跟父節(jié)點(diǎn)進(jìn)行交換(交換之后可能造成被交換的孩子節(jié)點(diǎn)不滿足堆的性質(zhì),因此每次交換之后要重新對被交換的孩子節(jié)點(diǎn)進(jìn)行調(diào)整)。有了初始堆之后就可以進(jìn)行排序了。

此時3位于堆頂不滿堆的性質(zhì),則需調(diào)整繼續(xù)調(diào)整

 這樣整個區(qū)間便已經(jīng)有序了。
    從上述過程可知,堆排序其實(shí)也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從R[1...n]中選擇最大記錄,需比較n-1次,然后從R[1...n-2]中選擇最大記錄需比較n-2次。事實(shí)上這n-2次比較中有很多已經(jīng)在前面的n-1次比較中已經(jīng)做過,而樹形選擇排序恰好利用樹形的特點(diǎn)保存了部分前面的比較結(jié)果,因此可以減少比較次數(shù)。對于n個關(guān)鍵字序列,最壞情況下每個節(jié)點(diǎn)需比較log2(n)次,因此其最壞情況下時間復(fù)雜度為nlogn。堆排序?yàn)椴环€(wěn)定排序,不適合記錄較少的排序。
 
測試程序
復(fù)制代碼
/*堆排序(大頂堆) 2011.9.14*/ 

#include <iostream>
#include<algorithm>
using namespace std;

void HeapAdjust(int *a,int i,int size) //調(diào)整堆
{
int lchild=2*i; //i的左孩子節(jié)點(diǎn)序號
int rchild=2*i+1; //i的右孩子節(jié)點(diǎn)序號
int max=i; //臨時變量
if(i<=size/2) //如果i是葉節(jié)點(diǎn)就不用進(jìn)行調(diào)整
{
if(lchild<=size&&a[lchild]>a[max])
{
max=lchild;
}
if(rchild<=size&&a[rchild]>a[max])
{
max=rchild;
}
if(max!=i)
{
swap(a[i],a[max]);
HeapAdjust(a,max,size); //避免調(diào)整之后以max為父節(jié)點(diǎn)的子樹不是堆
}
}
}

void BuildHeap(int *a,int size) //建立堆
{
int i;
for(i=size/2;i>=1;i--) //非葉節(jié)點(diǎn)最大序號值為size/2
{
HeapAdjust(a,i,size);
}
}

void HeapSort(int *a,int size) //堆排序
{
int i;
BuildHeap(a,size);
for(i=size;i>=1;i--)
{
//cout<<a[1]<<" ";
swap(a[1],a[i]); //交換堆頂和最后一個元素,即每次將剩余元素中的最大者放到最后面
//BuildHeap(a,i-1); //將余下元素重新建立為大頂堆
HeapAdjust(a,1,i-1); //重新調(diào)整堆頂節(jié)點(diǎn)成為大頂堆
}
}

int main(int argc, char *argv[])
{
//int a[]={0,16,20,3,11,17,8};
int a[100];
int size;
while(scanf("%d",&size)==1&&size>0)
{
int i;
for(i=1;i<=size;i++)
cin>>a[i];
HeapSort(a,size);
for(i=1;i<=size;i++)
cout<<a[i]<<"";
cout<<endl;
}
return 0;
}
復(fù)制代碼

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多