選擇排序,插入排序,氣泡排序,歸併排序,堆排序,基數排序的穩定性分析以及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,intlength) 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
這是因為,堆排序的兩個元素比較時,這兩個元素的位置之間隔了很多元素,並沒有考慮這些元素中是否有與這兩個元素相等的情況,因此會發生跳躍。