天天看點

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

原文位址為: 【每日算法】C語言8大經典排序算法(1)

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

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

1 交換類排序法

2 插入類排序法

3 選擇類排序法

一.交換類排序法

所謂交換排序法是指借助資料元素之間互相交換進行排序的方法。冒泡排序與快速排序法都屬于交換類排序方法。

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語言8大經典排序算法(1)

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-完成的最後令循環結束。)   圖示:

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

  舉例說明:

如無序數組[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

轉載請注明本文位址: 【每日算法】C語言8大經典排序算法(1)

繼續閱讀