归并排序

归并排序是一种利用分治思想来排序的算法。其核心思想是

       不断合并有序数据,直到所有数据有序为止。

       这里介绍二路归并,即初始有序长度为1,然后两两归并,如果重复,直到所有元素有序。

       二路归并的递归算法比较简洁,但是实用性很差。因为它调用了递归栈,需要额外的空间log2n次,再加上需要与数据等长度的额外数组,所以空间复杂度是o(n),归并算法的时间复杂度是o(n),一共要归并log2n次,所以时间复杂度是o(nlog2n).

       和快速排序和堆排序相比,它的唯一优势是它是一个稳定的排序算法,即相等元素的顺序不会在排序之后改变。所以,我们一般不在内部排序之中使用二路归并,这里我们通过介绍它来体会分治思想,因为归并在外部排序中很有用。

递归版本

#include <stdio.h>
#include <stdlib.h>
#define MAX 2<<30-1  //32位有符号最大整数

void merge(int a[], int left, int mid, int right)
{
	int i;
	int m = mid-left+1;//前半部分的长度
	int n = right - (mid+1)+1;//后半部分的长度
	int* arr1 = (int*)malloc(sizeof(int)*(m+1));//多分配一个位置给哨兵卫
	int* arr2 = (int*)malloc(sizeof(int)*(n+1));
	
	for (i=0; i<m+1; i++) arr1[i] = a[left+i];
	for (i=0; i<n+1; i++) arr2[i] = a[mid+i+1];
	arr1[m] = arr2[n] = MAX; //设置哨兵卫,防止边界条件的判断
	
	int p, q;
	p = q = 0;
	for (i=left; i<=right; i++)
	{
		if (arr1[p] <= arr2[q]){
			a[i] = arr1[p];
			p++;
		}
		else
		{
			a[i] = arr2[q];
			q++;
		}

	}	

	free(arr1);
	free(arr2);
	arr1 = arr2 = NULL;
}

void merge_sort(int a[], int left, int right)
{
	if (left < right)
	{
		int mid = (left+right)/2;
		merge_sort(a, left, mid);
		merge_sort(a, mid+1, right);
		merge(a, left, mid, right);//合并
	}
}

int main(void)
{
	int a[] = {1, 2, 9, 0, 3, 4, 12, 1, -23, 12, -89, -123};
	int i;
	int size = sizeof(a)/sizeof(int);
	merge_sort(a, 0, size-1);

	for (i=0; i<size; i++)
		printf("%d ", a[i]);
	getchar();
	return 0;
}

非递归版本

只是划分过程不一样,合并函数是一样的

void merge_sort(int a[], int n)
{
     if (n > 1)
     {
     int size=1,low,mid,high;
  
     while(size<=n-1)
     {
          low=0;
          while(low+size<=n-1)
          {
               mid=low+size-1;
               high=mid+size;
               if(high>n-1)//第二个序列个数不足size
                    high=n-1;         
               merge(a,low,mid,high);//调用归并子函数
               low=high+1;//下一次归并时第一关序列的下界
          }
          size*=2;//范围扩大一倍
     }
     }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值