归并排序

116 阅读2分钟

算法导论中,归并排序相关总结及实现

分治

将原问题分解为几个规模较小但类似于原问题的子问题,递归求解这些子问题,然后再合并这些子问题的解来建立原问题的解。 分治模式在每层递归都有三个步骤:

  1. 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例
  2. 解决这些子问题,递归求解这些子问题。然而,若子问题的规模足够小,则直接求解
  3. 合并这些子问题的解成原问题的解

归并排序算法:

分解:分解待排序的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;
}