歸併排序(merge sort)是利用「歸併」技術來進行排序,所謂歸併是指將若干個子檔案合併為乙個檔案的過程,由約翰·馮·諾伊曼發明。該演算法是採用分治法(divide and conquer)的乙個非常典型的應用。即是將檔案先分解再合併,最終得到有序序列。
題目描述
給出一組資料,根據由小到大順序輸出。
輸入要求:
輸入乙個整數n(資料長度)
輸入n個資料
輸出要求:
輸出由小到大排序後的資料
樣例輸入:
10樣例輸出:37 28 46 19 55 28 92 84 63 71
19 28 28 37 46 55 63 71 84 92基本思想
假設待排序的資料都存放在陣列r[n]中,mid是陣列長度的一半,將陣列分成r[0] ~ r[mid]和r[mid+1] ~ r[n-1]兩個子檔案,用遞迴的方式繼續將這兩個子檔案再各自分解成兩部分,直至子檔案中只有1個元素,這是分解的過程。然後將兩個子檔案合併成乙個有序檔案,直至形成有序序列,這是歸併的過程。
分解的過程利用遞迴操作即可實現。而排序的重點是歸併的過程,即如何將兩個檔案合併成乙個有序序列。以本例最後一次歸併過程為例(經過前幾次歸併後,這兩個子檔案自身都是有序的),i 和 j 分別指向兩個子檔案的第乙個元素,並定義乙個臨時陣列temp,i 和 j 位置元素進行比較,將較小的放入臨時陣列,然後向右繼續比較。
當乙個子檔案內所有元素都已放入臨時陣列temp中,另乙個子檔案剩餘元素無需再比較,因為經過前面的歸併子檔案本身是有序的,直接依次放入臨時陣列中即可。
歸併結束後將臨時陣列temp中的元素在放回元陣列r中。
參考**(c語言)
#include
void
merge_sort
(int r,
int start,
int end)
;//歸併排序
void
merge
(int r,
int start,
int mid,
int end)
;//歸併過程
intmain()
void
merge
(int r,
int start,
int mid,
int end)
while
(j<=end)
//第乙個檔案元素都已放入臨時陣列
temp[k++
]=r[j++];
//將第二個檔案剩餘元素放入臨時陣列
while
(i<=mid)
//第二個檔案元素都已放入臨時陣列
temp[k++
]=r[i++];
//將第乙個檔案剩餘元素放入臨時陣列
for(i=
0;i) r[start+i]
=temp[i]
;//將臨時陣列的元素放回原陣列r中
}void
merge_sort
(int r,
int start,
int end)
}
分析總結
歸併排序和快速排序都是分治思想應用在排序中的經典例項,所謂分治即「分而治之」,就是將乙個大問題分解成若干小問題,並且小問題要具有和大問題一樣的性質,然後將小問題的解合併得到大問題的解。本例中每次歸併操作都是將兩個子檔案合併成乙個有序檔案,這種方法稱為「二路歸併排序」。類似地也可以有「三路歸併排序」或「多路歸併排序」。
利用了分治思想,所以歸併排序的效率也是比較高的,利用遞迴需進行(log
2nlog_2n
log2n
)趟歸併,每趟歸併花費時間是o(n
nn),所以歸併排序最好和最壞情況下的時間複雜度均是o(nlo
g2nnlog _2n
nlog2
n)。平均時間複雜度o(nlo
g2nnlog _2n
nlog2
n)空間複雜度o(nnn)
二路歸併排序是穩定的。
寫在最後
排序演算法 歸併排序
歸併排序是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法 divide and conquer 的乙個非常典型的應用。首先考慮下如何將將二個有序數列合併。這個非常簡單,只要從比較二個數列的第乙個數,誰小就先取誰,取了後就在對應數列中刪除這個數。然後再進行比較,如果有數列為空,那直接將另...
排序演算法 歸併排序
include include define status int define max 20 typedef struct elemtype typedef struct sqlist void inital sqlist l 初始化 bool lt int i,int j void merge ...
排序演算法 歸併排序
歸併排序的思想其實完全是分治法的思想的體現,它完全遵循分治法的模式。這裡有必要再重提下分治法的思想 將原有的問題分解為幾個規模較小的但類似於原問題的子問題,遞迴的求解這些子問題,然後再合併這些子問題的解來求得原問題的解。現在來看看歸併排序的操作 1 將等待排序的含有 n 個元素的序列分解成各具有 n...