1. 程式人生 > 其它 >選擇排序,插入排序,氣泡排序,歸併排序,堆排序,基數排序的穩定性分析以及c語言程式碼

選擇排序,插入排序,氣泡排序,歸併排序,堆排序,基數排序的穩定性分析以及c語言程式碼

本題目為沙特教材《演算法設計與分析》第100頁的5.14題

1.選擇排序穩定性:不穩定

int SelectSort(int *A,int length)
{
    for(int i=1;i<=lenth-1;i++)
    {    int min=A[i];
        int k=i;
        for(int j=i+1;j<=length;j++)
        {
            if(A[j]<min)
            {
                min=A[j];
                k=j;
            }
        }
        
if(k!=i) { int temp=A[k]; A[k]=A[i]; A[i]=temp; } } }

 

舉例子:以A8    B8  C7為例 

第一步會把C和A交換  變成C B A 此時為 C7 B8 A8

第二步不做交換 

結束

 

對該例子的分析:   如當例子為8  9 8 7 時 最後一個元素與第一個元素就會發生交換,會忽視中間的元素,跳躍性交換,此時就會產生不穩定情況。

 

2.插入排序 

  

 1 int InsertSort(int *A,int
length) 2 { 3 for(j=2;j<=length;j++) 4 { 5 i=j; 6 temp=A[j]; 7 for(i=j;i>=2;i--) 8 { 9 if(temp<A[i-1]) //不用交換 只要把A[j]=A[j-1]即可 10 A[i]=A[i-1]; //A[i-1]右移 讓A[i-1]找到自己合適的位置 11 else 12 break
; 13 } 14 A[i]=temp; 15 } 16 }

插入排序是穩定的 因為是從第2個數開始,一一與前面的數比較,確定自己合適的位置。這種比較,屬於是與相鄰的數之間進行的比較、交換,而相鄰的數之間的比較、交換,與相鄰數之間的比較得出是否交換的結果,這種交換並非忽略了中間的元素,因此是穩定的。

3.氣泡排序 較簡單 為穩定的排序 此處不再解釋

4.歸併排序

int merge(int*A,int p,int q,int r) //合併A[p~q]和A[q+1~r]之間的元素
{    int B[100];
    int i,j,k;
    i=p;j=q+1;k=1;
    while(i<=q&&j<=r)
    {
        if(A[i]<=A[j])   
        {
            B[k++]=A[i++];
        }
        if(A[i]>A[j])
        {
            B[k++]=A[j++];
        }
    }    
    while(i<=q)
    {
        B[k++]=A[i++]; 
    }
    while(j<=r)
    {
        B[k++]=A[j++];
    }
    for(i=p,k=1;i<=r;)
    {
        A[i]=B[k];
        i++;
        k++;
    }
} 
int BottomupSort(int *A,int length)
{
    for(int i=1;i<length;i=i*2)
    {    
        j=1;
        while(j+2*i-1<=length)
        {
            merge(A,j,j+i-1,j+2*i-1);
            j=j+2*i;
        }
        if(j+i-1<length)  //此處可加等號可不加等號  加等號那麼當等號相等的時候 執行merge也直接退出了 
            merge(A,j,j+i-1,length);
    }
}
 

歸併排序是穩定的。

 

其實歸併排序的穩定與否,在於merge函式裡面的if比較等號寫到哪裡。

if(A[i]<=A[j])   
        {
            B[k++]=A[i++];
        }
        if(A[i]>A[j])
        {
            B[k++]=A[j++];
        }

以A3 B3 C1 D3為例  最開始 A3和B3 比較進行歸併(參考上面merge裡面是A[i]<=A[j] 取A[i]放入輔助B陣列中)得到A3 B3,  C1 和D3 比較歸併得到C1 D3, 然後這兩個再進行歸併 輔助陣列B中元素依次為C1  A3 B3 D3這裡為什麼A和B出現在D之前呢? 因為我們在merge函式裡 進行的是 判斷A[i]<=A[j]的時候 將A[i]放入輔助陣列中 ,即    if(A[1]<=A[4]) 和 if(A[2]<=A[4]) ,因為i的下標比j的小標小,所以我們優先取下標小的放在輔助陣列中,這樣就實現了穩定操作。    如果我們在merge函式裡寫的是   A[i]>=A[j]和A[i]<A[j]  這時候將會不穩定。

 5.堆排序

 堆排序是不穩定的,堆排序的演算法過程可以在我的《堆排序常用函式》隨筆中可見,此處不再寫其程式碼。以A13 B10 C7 D9 E8 F8為例 演算法過程步驟如下:

1.對初始混亂資料進行建堆:建堆結果為 A13 B10 F8 D9 E8 C7; 可以注意到 此時F8跑到了E8前面

2.首位元素和最後一個元素交換: 交換後的結果為 C7 B10 F8 D9 E8 A13 ,此時A13已經在正確的位置了

3.再對該資料建堆,此時不在用建堆函式,而只需要調整C7即可。  即呼叫Siftdown函式  新的堆為 B10 D9 F8 C7 E8

4。首位元素和最後一個元素再進行交換: E8  D9 F8 C7 B10,注意到此時E8又跑到了 F8前面 

5.建的新堆:D9 E8 F8 C7

6.交換 C7 E8 F8 D9

7.建新堆 E8 C7 F8

8.交換 F8 C7 E8

9.建新堆F8 C7

10.交換 C7 F8

11.結束

最終結果為 C7 F8 E8 D9 B10 A13  

這是因為,堆排序的兩個元素比較時,這兩個元素的位置之間隔了很多元素,並沒有考慮這些元素中是否有與這兩個元素相等的情況,因此會發生跳躍。