归并排序

归并排序也是分治策略的一种应用,基本思想是:一个已经排序好的数组可以由他的两个已经排序好的子数组得到(依次从两个子数组中拿出较小(或较大,取决于排序方式)的元素放回到父数组中,如果一个数组中的元素已经全部拿刀父数组中去了,就把剩下的元素全部放回到父数组的后面);而排序好的子数组当然也可以用同样的方式得到,也就是说要将待排序的数组不断划分,直到划分成的子数组中只有一个元素为止。

#include<stdio.h>
#include<stdlib.h>
#define random(n) (rand()%n)
#define N	12
#define NOTATION 99999999

//这个做法在每个子数组的后面设置了哨兵,当有效的数组全部被复制会父数组的之后,
//达到了这个哨兵,由于这个哨兵是一个非常大的数字,所以在与另外一个没有复制完成的
//数组进行比较的时候,每次都是将没有复制完成的数组中的元素复制会父数组
//这种做法的优点是不需要每复制一次就判断子数组有没有复制完成
/*
void merge(int *a,int p,int q,int r){
	int n1=q-p+1;
	int n2=r-q;
	int *L=(int *)malloc(sizeof(int)*n1);
	int *R=(int *)malloc(sizeof(int)*n2);
	int i,j,k;

	for(i=0;i<n1;i++){
		L[i++]=a[p+i];
		i--;
	}
		
	for(j=0;j<n2;j++){
		R[j++]=a[q+j+1];
		j--;
	}
		
	L[n1]=NOTATION;			//设置哨兵
	R[n2]=NOTATION;
	i=0;
	j=0;
	for(k=p;k<=r;k++){
		if(L[i]<=R[j]){
			a[k]=L[i];
			i++;
		}
		else{
			a[k]=R[j];
				j++;
		}
	}
}
*/

//这个做法没有设置哨兵,但是需要在每次复制完成之后判断两个子数组是否已经复制完成,
//如果有一个子数组已经复制完成,那么将另外的一个子数组中的元素全部复制到父数组中
void merge(int *a,int p,int q,int r){
	int n1=q-p+1;
	int n2=r-q;
	int *L=(int *)malloc(sizeof(int)*n1);
	int *R=(int *)malloc(sizeof(int)*n2);
	int i,j,k;
	
	for(i = 0;i < n1; i++){
		L[i++] = a[p+i];
		i--;
	}
		
	for(j = 0;j < n2; j++){
		R[j++] = a[q+j+1];
		j--;
	}
		
	i=0;
	j=0;
	for(k = p; k <= r; k++){
		if(L[i] <= R[j]){
			a[k]=L[i];
			i++;
		}
		else{
			a[k] = R[j];
				j++;
		}
		if(i >= n1){  //L已经复制完了
			for(k++; j < n2; j++, k++)
				a[k] = R[j];
			break;
		}
		else if(j >= n2) { //R已经复制完了
			for(k++; i < n1; i++, k++)
				a[k] = L[i];
			break;
		}
	}
}

void merge_sort(int *A,int p,int r){
	int q;
	if(p < r){
		q=(p+r)/2;
		merge_sort(A, p, q);
		merge_sort(A, q+1, r);
		merge(A, p, q, r);
	}	
}

void main(){
	int n=0;
	int i=0;
	int j=0;
	int a[N];					
	printf("排序前:\n");
	for(n = 0; n < N; n++){
		a[n] = random(100);
		printf("%-5d", a[n]);
		
	}
	
	printf("\n");
	merge_sort(a, 0, N);
	printf("排序后:\n");
	for(i=1; i <= N; i++)
		printf("%-5d", a[i]);
	printf("\n");		
}

代码中的merge方法用于将两个已经排序好的子数组合并成一个排序好的数组,上面提供了两种方式,两种方式的区别在注释中有说明。

复杂度分析:

当问题规模为n时,代码中将每个问题都划分为两个规模为n/2的子问题,将问题分解需要的时间为C(n),将问题合并需要的时间为D(n),所以T(n) = 2*T(n/2) + C(n) + D(n),也即T(n) = Ɵ(nlgn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值