算法导论中,归并排序相关总结及实现
分治
将原问题分解为几个规模较小但类似于原问题的子问题,递归求解这些子问题,然后再合并这些子问题的解来建立原问题的解。 分治模式在每层递归都有三个步骤:
- 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例
- 解决这些子问题,递归求解这些子问题。然而,若子问题的规模足够小,则直接求解
- 合并这些子问题的解成原问题的解
归并排序算法:
分解:分解待排序的n个元素的序列成,各自具有n/2个元素的两个子序列
解决:使用归并排序递归的排序两个子序列
合并:合并两个已排序的子序列以产生已排序的答案
伪代码:
MERGE(A, p, q, r)
n1=q-p+1;
n2=r-q;
let L[1...n1+1] and R[1..n2+1] be new arrays
for i=1 to n1
L[i] = A[p+i-1]
for j=1 to n2
R[j] = A[q+j]
L[n1+1]=MAX //避免以下对A[]赋值时越界
R[n2+1]=MAX
i=1
j=1
for k=p to r
if L[i]<=R[j]
A[k]=L[i]
i=i+1
else
A[k]=R[j]
j=j+1
MERGE_SORT(A, p, r)
if(p>=r)
return
q=(p+r)/2
MERGE_SORT(A,p,q)
MERGE_SORT(A,q+1,r)
MERGE(A,p,q,r)
时间复杂度:
O(nlgn)==>递归分解子问题,形成一颗二叉树,高度为logn,每一层merge时间O(n)
C代码实现
#include <stdio.h>
#include <limits.h>
void merge(int *nums, int p, int q, int r){
int *L = malloc(sizeof(int)*(q-p+2));
int *R = malloc(sizeof(int)*(r-q+1));
int i=0, j=0, k=0;
for(k=p;k<=q;k++){
L[i++]=nums[k];
}
L[q-p+1] = INT_MAX;
for(k=q+1;k<=r;k++){
R[j++] = nums[k];
}
R[r-q] = INT_MAX;
i=0,j=0;
for(k=p;k<=r;k++){
if(L[i]<=R[j]){
nums[k] = L[i];
i++;
}else{
nums[k] = R[j];
j++;
}
}
}
void mergesort(int *nums, int start, int end){
if(start>=end)
return;
int q = (start+end)/2;
mergesort(nums, start, q);
mergesort(nums, q+1, end);
merge(nums, start, q, end);
}
int main(){
int nums[]={3,2,6,8,1,3,4,10};
int start=0;
int end = sizeof(nums)/sizeof(int)-1;
mergesort(nums, start, end);
int i;
for(i=0; i<=end;i++){
printf("%d ", nums[i]);
}
printf("\n");
return 0;
}