排序——归并排序

    归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并过程:
例如有两个有序表:(7,10,13,15)和(4,8,19,20),归并后得到的有序表为:(4,7,8,10,13,15,19,20)。
归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。
但是上面这个思路的前提是已经有了两个有序的子表,但是在实际排序过程中往往不可能已经有了两个有序子表,所以最好的办法就是先假设子表的长度都为1,因为一个元素总是有序的,然后通过归并得到更长的子表,依次类推,最终得到一个整体的有序序列。
程序代码如下:
#include <stdio.h>

#define	N	17

void print(int a[], int n)
{  
    int j;

	for(j=0; j < n; j++)
	{  
        if(a[j])
			printf("%2d ", a[j]); 
    }  
    printf("\n");  
}  
  
/*将src[i…m]和src[m +1 …n]归并到辅助数组des[i…n]*/  
void two_merge(int *src, int *des, int i, int m, int n)  
{  
    int j, k;

    for(j=m+1, k=i; i<=m && j<=n ; k++)
	{  
        if(src[j] < src[i]) 
			des[k] = src[j++];  
        else 
			des[k] = src[i++];  
    }  
    while(i <= m)  
		des[k++] = src[i++];  
    while(j <= n)  
		des[k++] = src[j++];
	printf("合并结果:   ");
    print(des, N);  
}  
  
void merge_sort(int *s, int *d, int length)  
{   
    int step = 1;   
    int *tmp, *src = s, *des = d; 
	int i;

	/*先将src[0],src[1]合并为src1,src[2],src[3]合并为src2...,再将src1,src2合并...*/
    while(step < length) 
	{     
        i = 0;
		step *= 2; /*step的起始步长应该为2*/
        while(i+step <= length) /*length/step能够整除的部分先合并*/
		{  
            two_merge(src, des, i, i+step/2-1, i+step-1);  
            i = i + step;  
        }
		
        if((i+step/2) < length) /*i==length表示刚好整除*/
			                    /*除不够且能够合并的在这里合并*/
								/*不能合并的状态举例:以step=4合并但是只余了<=2个元素*/
		{  
			two_merge(src, des, i, i+step/2-1, length-1); /*i+step/2-1>length-1的时候two_merge函数会排错*/ 
        }  
        tmp = src; 
		src = des; 
		des = tmp; /*交换src和des数组*/
    }
}  
  
  
int main()
{  
    int src[N] = {1, 3, 7, 6, 8, 10, 2, 5, 4, 9, 12, 11, 13, 17, 15, 14, 16};  
    int des[N] = {0};
	
	merge_sort(src, des, N); 
    printf("排序之后的src:");
	print(src, N);  
    printf("排序之后的des:");  
    print(des, N);  

	return 0;  
} 

程序运行结果:

N=13时


N=17时

分析:从程序输出的结果看,排好序的结果可能最终存放于src数组,也可能最终存放于des数组,这是因为在归并排序的时候,不停的再交换src和des数组,即把一个的合并结果放到另一个数组,另一个的合并结果又反过来放到当前的数组,如此交替,如果需要制定最终结果放到哪个数组,那么可以在merge_sort函数的末尾判断s与src的关系,再进行一次数据复制即可。

归并排序的特点:

时间复杂度:O(nlog(2^n)),因为对于归并排序来说,一个元素比较log(2^n)就会放到最终的位置上,一共有n个元素。

空间复杂度:O(n),用到了一个辅助数组。

稳定性:稳定。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值