1. 程式人生 > >排序演算法-合併排序(C語言實現)

排序演算法-合併排序(C語言實現)

都說“演算法是程式的靈魂”,而排序是計算機儲存控制方面不能沒有的操作。它在資料的存取,查詢搜尋,資料統計這些基礎資料操作方面有著重要的應用。所以排序演算法是必須是很有研究的。

這次,我學習的是-歸併排序演算法。據說該演算法是馮諾依曼發明的。這個排序演算法比起直接的冒泡法的優勢,在於它的時間複雜度上的優勢O(N*logN)。冒泡法要N!當N很大時候,時間差異很大。當然歸併排序在空間複雜度上是絕對的劣勢O(N*logN),冒泡法幾乎不多佔用額外記憶體。

合併演算法的描述:
順序描述(演繹)
1. 將要排序的N個數據分成N/2個組(1,2)(3,4)(5,6)、、、(n,n-1)分別排好序
2. 將分別排好序的N/2個組,分成(N/2)/2個組,然後分別排序。排序的方式:建立一個容器,然後第一個位置(最小),是來自兩個已經排好序的序列中“首位”較小的那個,抽取了誰,誰的首位就要讓位給後一個,然後再選次最小的放在第二個位置
3. 將分別排好序的(N/2)/2個組,接著分別合併,然後排序、、、
4. 直到合併成最大的陣列
這就是為什麼這個叫“合併排序”了。

逆向描述(遞迴)
1. 如果要排序的序列已經是部分“排好”了,那麼接下來的排序,我們就沒必要用“最蠢”方法遍歷對比了,而只要比較最多N/2次就行。
2. 所以我們先把部分排好序,然後利用上面提到的方法排序,就得到全排序了。
3. 部分排序可以採用同樣方法,先將小部分排好序,這樣就可以用上面的方式排序目前的部分
4. 、、、同樣的方式直到兩兩比較。然後就用直接方法排好,當然稍加註意把這個也劃歸到上面的排序中也可以。

採用遞迴或是迴圈的方式不是區分是否是歸併演算法的關鍵。但是一般這個演算法我們都用遞迴實現。上面說的空間複雜度也是在遞迴中產生的。

#define length 100 //在這裡進行巨集定義,因為load.h裡用到。當然可以在load.h的開始定義              
#include <stdio.h> #include "load.h" int list[length]; void sort(int *l,int n);//宣告 int main() { int i; load(list); //將隨機資料從.txt載入,假定都是整型資料 sort(&list[0],(int)length); //呼叫排序函式,把隨機數列從小到大排好 printf("the sorted list is :\n"); for(i=0;i<length;i++) { printf
("%d\t",list[i]); } printf("\n"); return 0; } /*合併排序演算法的實現*/ void sort(int *l,int n) { int tp[n]; int i = 0,j = 0,c = 0; int temp1,temp2,temp; int *left,*right; temp1 =(int)(n/2); //中間分割的方法 temp2 = n - temp1; left = &l[0]; right= &l[temp1]; if (2 < n) { sort(left,temp1); //遞迴呼叫本函式去解決更小的問題 sort(right,temp2); while ( temp1 != i && temp2 != j ) { if (left[i]<=right[j]) { tp[c] = left[i]; i++; } else { tp[c] = right[j]; j++; } c++; } if (temp1 == i) { for(c=0;c<temp1+j;c++) { l[c]=tp[c]; } } else { for(c=i;c<temp1;c++) l[c+j]=l[c]; for(c=0;c<temp2+i;c++) { l[c]=tp[c]; } } } if (n = 1) if (n = 2) { if (l[0]<=l[1]) return; else { temp = l[0]; l[0] = l[1]; l[1] = temp; } } }