C實現的8大算法

【每日算法】C語言8大經典排序算法(1)

算法一直是編程的基礎,而排序算法是學習算法的開始,排序也是數據處理的重要內容。所謂排序是指將一個無序列整理成按非遞減順序排列的有序序列。排列的方法有很多,根據待排序序列的規模以及對數據的處理的要求,可以採用不同的排序方法。那麼就整理下網上搜索的資料,按自己的理解,把C語言的8大排序算法列出來。

普通意義上,排序算法可以分爲三大類:

1 交換類排序法
2 插入類排序法
選擇類排序法

一.交換類排序法

所謂交換排序法是指藉助數據元素之間互相交換進行排序的方法。冒泡排序與快速排序法都屬於交換類排序方法。

 

1、冒泡排序(BubbleSort)

冒泡排序的基本概念:

依次比較相鄰的兩個數,將小數放在前面,大數放在後面。即在第一趟:首先比較第1個和第2個數,將小數放前,大數放後。然後比較第2個數和第3個數,將小數放前,大數放後,如此繼續,直至比較最後兩個數,將小數放前,大數放後。至此第一趟結束,將最大的數放到了最後。在第二趟:仍從第一對數開始比較(因爲可能由於第2個數和第3個數的交換,使得第1個數不再小於第2個數),將小數放前,大數放後,一直比較到倒數第二個數(倒數第一的位置上已經是最大的),第二趟結束,在倒數第二的位置上得到一個新的最大數(其實在整個數列中是第二大的數)。如此下去,重複以上過程,直至最終完成排序。由於在排序過程中總是小數往前放,大數往後放,相當於氣泡往上升,所以稱作冒泡排序。

實現:

外循環變量設爲i,內循環變量設爲j。假如有10個數需要進行排序,則外循環重複9次,內循環依次重複9,8,...,1次。每次進行比較的兩個元素都是與內循環j有關的,它們可以分別用a[j]和a[j+1]標識,i的值依次爲1,2,...,9,對於每一個i,j的值依次爲1,2,...10-i。

圖示:

C語言實現:

複製代碼
 1 void Bublesort(int a[],int n)
 2 {
 3      int i,j,k;
 4      for(j=0;j<n;j++)   /* 氣泡法要排序n次*/
 5      {
 6           for(i=0;i<n-j;i++)  /* 值比較大的元素沉下去後,只把剩下的元素中的最大值再沉下去就可以啦 */
 7           {
 8                if(a[i]>a[i+1])  /* 把值比較大的元素沉到底 */
 9                {
10                     k=a[i];
11                     a[i]=a[i+1];
12                     a[i+1]=k;
13                }
14           }
15      }
16 }
複製代碼

性能分析:

若記錄序列的初始狀態爲"正序",則冒泡排序過程只需進行一趟排序,在排序過程中只需進行n-1次比較,且不移動記錄;反之,若記錄序列的初始狀態爲"逆序",則需進行n(n-1)/2次比較和記錄移動。因此冒泡排序總的時間複雜度爲O(n*n)。

博客園中,有一篇博文是關於冒泡算法的優化,可以看下,兩種優化:

白話經典算法系列之一 冒泡排序的三種實現

 

2、快速排序(Quicksort)

基本思想:

快速排序是對冒泡排序的一種改進。由C. A. R. Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。

實現:
設要排序的數組是A[0]……A[N-1],首先任意選取一個數據(通常選用第一個數據)作爲關鍵數據,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱爲一趟快速排序。值得注意的是,快速排序不是一種穩定的排序算法,也就是說,多個相同的值的相對位置也許會在算法結束時產生變動。
一趟快速排序的算法是:
1)設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
2)以第一個數組元素作爲關鍵數據,賦值給key,即 key=A[0];
3)從j開始向前搜索,即由後開始向前搜索(j -- ),找到第一個小於key的值A[j],A[i]與A[j]交換;
4)從i開始向後搜索,即由前開始向後搜索(i ++ ),找到第一個大於key的A[i],A[i]與A[j]交換;
5)重複第3、4、5步,直到 I=J; (3,4步是在程序中沒找到時候j=j-1,i=i+1,直至找到爲止。找到並交換的時候i, j指針位置不變。另外當i=j這過程一定正好是i+或j-完成的最後令循環結束。)
 
圖示:
 
舉例說明:

如無序數組[6 2 4 1 5 9]

a),先把第一項[6]取出來,

用[6]依次與其餘項進行比較,

如果比[6]小就放[6]前邊,2 4 1 5都比[6]小,所以全部放到[6]前邊

如果比[6]大就放[6]後邊,9比[6]大,放到[6]後邊,//6出列後大喝一聲,比我小的站前邊,比我大的站後邊,行動吧!霸氣十足~

一趟排完後變成下邊這樣:

排序前 6 2 4 1 5 9

排序後 2 4 1 5 6 9

 

b),對前半拉[2 4 1 5]繼續進行快速排序

重複步驟a)後變成下邊這樣:

排序前 2 4 1 5

排序後 1 2 4 5

前半拉排序完成,總的排序也完成:

排序前:[6 2 4 1 5 9]

排序後:[1 2 4 5 6 9]

C語言實現:
複製代碼
 1  int partition(int *data,int low,int high)
 2 
 3   { 
 4        int t = 0;
 5 
 6   t = data[low];
 7 
 8   while(low < high)
 9 
10   { while(low < high && data[high] >= t)
11 
12   high--;
13 
14   data[low] = data[high];
15 
16   while(low < high && data[low] <= t)
17 
18   low++;
19 
20   data[high] = data[low];
21 
22   }
23 
24   data[low] = t;
25 
26   return low;
27 
28   }
29 
30   void sort(int *data,int low,int high) //快排每趟進行時的樞軸要重新確定,由此進 //一步確定每個待排小記錄的low及high的值
31 
32   { if(low >= high)
33 
34   return ;
35 
36   int pivotloc = 0;
37 
38   pivotloc = partition(data,low,high);
39 
40   sort(data,low,pivotloc-1);
41 
42   sort(data,pivotloc+1,high);
43 
44   }
複製代碼

性能分析

快速排序的時間主要耗費在劃分操作上,對長度爲k的區間進行劃分,共需k-1次關鍵字的比較。

最壞情況是每次劃分選取的基準都是當前無序區中關鍵字最小(或最大)的記錄,劃分的結果是基準左邊的子區間爲空(或右邊的子區間爲空),而劃分所得的另一個非空的子區間中記錄數目,僅僅比劃分前的無序區中記錄個數減少一個。時間複雜度爲O(n*n)

在最好情況下,每次劃分所取的基準都是當前無序區的"中值"記錄,劃分的結果是基準的左、右兩個無序子區間的長度大致相等。總的關鍵字比較次數:O(nlgn)

儘管快速排序的最壞時間爲O(n2),但就平均性能而言,它是基於關鍵字比較的內部排序算法中速度最快者,快速排序亦因此而得名。它的平均時間複雜度爲O(nlgn)。

這裏有一個視頻比較形象地說明了這兩個有趣的排序算法:http://www.tudou.com/programs/view/htKY1-Rj9ZE/?resourceId=0_06_02_99

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章