常見演算法:C語言中的排序演算法--氣泡排序,選擇排序,希爾排序
氣泡排序(Bubble Sort,臺灣譯為:泡沫排序或氣泡排序)是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端
/* 用選擇法對10個數進行排序 */ #include<stdio.h> void main() { int i,j,a[10]; for(i=0;i<10;i++) scanf("%d",&a[i]); for(i=0;i<9;i++) {//n個數要進行n-1趟比較 for(j=0;j<=9-i;j++) //每趟比較n-i次 if(a[j]>a[j+1]) //依次比較兩個相鄰的數,將小數放在前面,大數放在後面 { int t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } for(i=0;i<10;++i) //輸出比較之後的陣列 printf(" %d",a[i]); }
另一種常見的寫法
/* 氣泡排序的另外一種寫法 */ #include<stdio.h> void BubbleSort(int a[],int n) { int i,j; for(i=n-1;i>0;--i) //從n-1迴圈的到0,也是n次 for(j=0;j<i;j++) if(a[j]>a[j+1]) { int temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } void main() { int a[10],i; for(i=0;i<10;i++) scanf("%d",&a[i]); BubbleSort(a,10); printf("排序後的陣列:\n"); for(i=0;i<10;i++) printf(" %d",a[i]); }
選擇排序(Selection sort)是一種簡單直觀的排序演算法。它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小元素,然後放到排序序列末尾(目前已被排序的序列)。以此類推,直到所有元素均排序完畢。
#include<stdio.h> void SelectSort(int a[],int n) { int i,j; for(i=0;i<n-1;i++) //n個數要進行n-1趟比較,每次確定一個最小數放在a[i]中 { int k=i; //假設a[0]是最小的數,把下標0放在變數K裡面, for(j=i+1;j<n;j++) if(a[k]>a[j]) k=j; //如果a[k]>a[j] 前面的數比後面的數大,交換下標,此時k指向小的數 if(k!=i) { int temp=a[i]; a[i]=a[k]; a[k]=temp; } } } void main() { int a[10],i; for(i=0;i<10;i++) scanf("%d",&a[i]); SelectSort(a,10); printf("排序後的陣列:\n"); for(i=0;i<10;i++) printf(" %d",a[i]); }
希爾排序通過將比較的全部元素分為幾個區域來提升插入排序的效能。這樣可以讓一個元素可以一次性地朝最終位置前進一大步。然後演算法再取越來越小的步長進行排序,演算法的最後一步就是普通的插入排序,但是到了這步,需排序的資料幾乎是已排好的了(此時插入排序較快)。
假設有一個很小的資料在一個已按升序排好序的陣列的末端。如果用複雜度為O(n2)的排序(氣泡排序或插入排序),可能會進行n次的比較和交換才能將該資料移至正確位置。而希爾排序會用較大的步長移動資料,所以小資料只需進行少數比較和交換即可到正確位置。
一個更好理解的希爾排序實現:將陣列列在一個表中並對列排序(用插入排序)。重複這過程,不過每次用更長的列來進行。最後整個表就只有一列了。將陣列轉換至表是為了更好地理解這演算法,演算法本身僅僅對原陣列進行排序(通過增加索引的步長,例如是用i += step_size
而不是i++
)。
例如,假設有這樣一組數[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我們以步長為5開始進行排序,我們可以通過將這列表放在有5列的表中來更好地描述演算法,這樣他們就應該看起來是這樣:
13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
然後我們對每列進行排序:
10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
當我們以單行來讀取資料時我們得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].這時10已經移至正確位置了,然後再以3為步長進行排序:
10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
排序之後變為:
10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
最後以1步長進行排序(此時就是簡單的插入排序了)。
//希爾排序
#include<stdio.h>
#define LT(a,b) ((a)<(b))
#define MAX_SIZE 20
#define T 3
#define N 10
typedef int KeyType;
typedef int InfoType;
typedef struct
{
KeyType key;
InfoType otherinfo;
}RedType;
typedef struct
{
RedType r[MAX_SIZE+1];
int length;
}SqList;
void PrintSqList(SqList L)
{
int i;
for(i=1;i<L.length;i++)
{
printf("(%d %d)",L.r[i].key,L.r[i].otherinfo);
}
printf("\n");
}
int PrintSqlListKey(SqList L)
{
int i;
for(i=1;i<L.length;i++)
{
printf("%d ",L.r[i].key);
}
printf("\n");
return 0;
}
void ShellInsert(SqList &L,int dk)
{
int i,j;
for(i=dk+1;i<=L.length;i++)
{
if LT(L.r[i].key,L.r[i-dk].key)
{
L.r[0]=L.r[i];
for(j=i-dk;j<0&& LT(L.r[i].key,L.r[j].key);j-=dk)
{
L.r[j+dk]=L.r[j];
}
L.r[j+dk]=L.r[0];
}
}
}
void ShellSort(SqList &L,int dlta[],int t)
{
int k;
for(k=0;k<t;k++) //對所有增量序列
{
ShellInsert(L,dlta[k]);
printf("dlta[%d]=%d,第%d趟排序結果(僅輸出關鍵字):",k,dlta[k],k+1);
PrintSqlListKey(L);
}
}
void main()
{
RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,65},{13,6},{27,7},{49,8},{55,9},{4,10}};
SqList m;
int i,dt[T]={5,3,1};
for(i=0;i<N;i++)
{
m.r[i+1]=d[i];
}
m.length=N;
printf("希爾排序前:\n");
PrintSqList(m);
printf("\n");
ShellSort(m,dt,T);
printf("希爾排序後:\n");
PrintSqList(m);
printf("\n");
}