排序(五) 之归并排序


 
 

一、归并排序(Merge Sort)

  归并排序是一个相当“稳定”的算法对于其它排序算法,比如希尔排序,快速排序和堆排序而言,这些算法有所谓的最好与最坏情况。而归并排序的时间复杂度是固定的,它是怎么做到的?

 

二、算法原理

  首先来看归并排序要解决的第一个问题:两个有序的数组怎样合成一个新的有序数组,比如数组1{ 3,5,7,8 }、数组2为{ 1,4,9,10 },首先那肯定是创建一个长度为8的新数组咯,然后就是分别从左到右比较两个数组中哪一个值比较小,然后复制进新的数组中,比如我们这个例子:
  { 3,5,7,8 } { 1,4,9,10 }
  { }一开始新数组是空的。然后两个指针分别指向第一个元素,进行比较,显然,1比3小,所以把1复制进新数组中:
  { 3,5,7,8 } { 1,4,9,10 } { 1, }
  第二个数组的指针后移,再进行比较,这次是3比较小:
  { 3,5,7,8 } { 1,4,9,10 } { 1,3, }
  同理,我们一直比较到两个数组中有某一个先到末尾为止,在我们的例子中,第一个数组先用完。{ 3,5,7,8 } { 1,4,9,10 } { 1,3,4,5,7,8 }
  最后把第二个数组中的元素复制进新数组即可。
  { 1,3,4,5,7,8,9,10 }

  由于前提是这个两个数组都是有序的,所以这整个过程是很快的,我们可以看出,对于一对长度为N的数组,进行合并所需要的比较次数最多为2 * N -1。这其实就是归并排序的最主要想法和实现,归并排序的做法是:
  将一个数组一直对半分,问题的规模就减小了,再重复进行这个过程,直到元素的个数为一个时,一个元素就相当于是排好顺序的。接下来就是合并的过程了,合并的过程如同前面的描述。一开始合成两个元素,然后合并4个,8个这样进行。所以可以看到,归并排序是“分治”算法的一个经典运用。

 

三、代码示例

/*合拼有序数组*/
int merge_array(int *array, int start, int middle, int end, int *temp)
{   
    int i, j, k = 0;
     
    i = start; 
    j = middle + 1;
     
    while(i <= middle && j <= end) {
        if (array[i] <= array[j])
            temp[k ++] = array[i ++];
        else 
            temp[k ++] = array[j ++];
    }
     
    while (i <= middle) 
        temp[k ++] = array[i ++];
     
    while (j <= end) 
        temp[k ++] = array[j ++];
     
    for (i = 0; i < k; i ++) 
        array[start + i] = temp[i];
     
    return 0;
}
 
 
/*将需要排序的数据递归对半拆分, 再进行合拼*/
int _merge_sort(int *array, int start, int end, int *temp)
{   
    int middle;
     
    if (start < end) {
        middle = (end + start) / 2;
        _merge_sort(array, start, middle, temp);
        _merge_sort(array, middle + 1, end, temp);
        merge_array(array, start, middle, end, temp);
    }
    return 0;
}
 
 
int mergeSort(int *array, int length)
{
    int *temp;
    if (NULL == array || length <= 0)
        return -1;
    temp = (int *)malloc(sizeof(int) * length);
    if (NULL == temp) {
        perror("malloc error");
        return -1;
    }
    memset(temp, 0, sizeof(int) * length);
    _merge_sort(array, 0, length - 1, temp);
    free(temp);
    return 0;
}

 

四、实例测试

sort.c

int main(int argc, char **argv)
{
	int i, length;
    // int buf[5] = {
    //      16, 32, 8, 12, 13 
    // };
	int buf[] = {112, 5,1,11, 34, 10, 111,1234,44,33,23,56,77,88,43,41,2,4,19,13,3,8,6,0,9};
	//int buf[10]={4,1,3,2,16,9,10,14,8,7};
	
	length = sizeof(buf)/sizeof(int);
	// heap_sort(buf-1, length);
    // shell_sort(buf, length, 2);
    // quick_sort(buf, 0, length - 1);
    printf("start merge sort...\n\n");
    mergeSort(buf, length);

	for(i = 0; i < length; i++)
		printf("%d\t ", buf[i]);	
	printf("\n");	

	return 0;
}

测试结果:
在这里插入图片描述

 
 
 
 
 
 
 
关注公众号"小败日记",搬砖过程遇到的问题,大家一起探讨,资源共享

小败日记公众号

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值