基本思想
歸并排序(MERGE-SORT)是利用歸并的思想實(shí)現(xiàn)的排序方法苗沧,該算法采用經(jīng)典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然后遞歸求解愉舔,而治(conquer)的階段則將分的階段得到的各答案"修補(bǔ)"在一起,即分而治之)察郁。
分而治之
1024555-20161218163120151-452283750.png
可以看到這種結(jié)構(gòu)很像一棵完全二叉樹衍慎,本文的歸并排序我們采用遞歸去實(shí)現(xiàn)(也可采用迭代的方式去實(shí)現(xiàn))。分階段可以理解為就是遞歸拆分子序列的過程绳锅,遞歸深度為log2n西饵。
合并相鄰有序子序列
再來看看治階段酝掩,我們需要將兩個(gè)已經(jīng)有序的子序列合并成一個(gè)有序序列鳞芙,比如上圖中的最后一次合并,要將[4,5,7,8]和[1,2,3,6]兩個(gè)已經(jīng)有序的子序列,合并為最終序列[1,2,3,4,5,6,7,8]原朝,來看下實(shí)現(xiàn)步驟驯嘱。
1024555-20161218194508761-468169540.png
代碼實(shí)現(xiàn)
OC:
- (void)mergeSort:(NSMutableArray *)arr{
NSMutableArray *temp = [NSMutableArray arrayWithCapacity:arr.count];//在排序前,先建好一個(gè)長度等于原數(shù)組長度的臨時(shí)數(shù)組喳坠,避免遞歸中頻繁開辟空間
[self sort:arr Left:0 Right:(int)arr.count-1 Temp:temp];
}
- (void)sort:(NSMutableArray *)arr Left:(int)left Right:(int)right Temp:(NSMutableArray *)temp{
if(left<right){
int mid = (left+right)/2;
[self sort:arr Left:left Right:mid Temp:temp];//左邊歸并排序鞠评,使得左子序列有序
[self sort:arr Left:mid+1 Right:right Temp:temp]; //右邊歸并排序,使得右子序列有序
[self merge:arr Left:left Mid:mid Right:right Temp:temp];//將兩個(gè)有序子數(shù)組合并操作
}
}
- (void)merge:(NSMutableArray *)arr Left:(int)left Mid:(int)mid Right:(int)right Temp:(NSMutableArray *)temp{
int i = left;//左序列指針
int j = mid+1;//右序列指針
int t = 0;//臨時(shí)數(shù)組指針
while (i<=mid && j<=right){
if(arr[i]<=arr[j]){
temp[t++] = arr[i++];
}else {
temp[t++] = arr[j++];
}
}
while(i<=mid){//將左邊剩余元素填充進(jìn)temp中
temp[t++] = arr[i++];
}
while(j<=right){//將右序列剩余元素填充進(jìn)temp中
temp[t++] = arr[j++];
}
t = 0;
//將temp中的元素全部拷貝到原數(shù)組中
while(left <= right){
arr[left++] = temp[t++];
}
}
swift:
func mergeSort(arr:inout Array<Int>){
var temp = [Int](repeating: 0, count: arr.count)
self.sort(arr: &arr, left: 0, right:(arr.count-1), temp: &temp)
}
func sort(arr:inout [Int],left:Int,right:Int,temp:inout [Int]){
if left<right {
let mid:Int = (left + right)/2;
sort(arr: &arr, left: left, right: mid, temp: &temp)
sort(arr: &arr, left: mid+1, right: right, temp: &temp)
merge(arr: &arr, left:left, mid: mid, right: right, temp: &temp)
}
}
func merge(arr:inout [Int],left:Int,mid:Int,right:Int,temp:inout [Int]) {
var i = left
var j = mid + 1
var t = 0
while i<=mid && j<=right{
if(arr[i]<=arr[j]){
temp[t] = arr[i];
t = t+1
i = i+1
}else {
temp[t] = arr[j];
t = t+1
j = j+1
}
}
while i<=mid {
temp[t] = arr[i];
t = t+1
i = i+1
}
while j<=right {
temp[t] = arr[j];
t = t+1
j = j+1
}
t = 0;
var left = left
while left <= right{
arr[left] = temp[t];
left=left+1
t=t+1
}
}
最后
歸并排序是穩(wěn)定排序壕鹉,它也是一種十分高效的排序剃幌,能利用完全二叉樹特性的排序一般性能都不會(huì)太差。從上文的圖中可看出晾浴,每次合并操作的平均時(shí)間復(fù)雜度為O(n)负乡,而完全二叉樹的深度為|log2n|〖够耍總的平均時(shí)間復(fù)雜度為O(nlogn)抖棘。而且,歸并排序的最好狸涌,最壞切省,平均時(shí)間復(fù)雜度均為O(nlogn)。