归并排序(c语言)

归并排序的基本原理是把两个有序数组合为一个有序数组。

例如我们现在将数组a{2, 4, 6, 8}与数组b{1, 3, 5, 7}合成一个有序数组c。 我们依次比较a,b中的元素,谁小将谁放入新数组c中,直到a数组与b数组中的一个被取完。再将剩下的一个数组中的元素依次放入新数组c。

Mergr(int a[], int b[], int m, int n)   //m为a数组的长度 - 1,n为b数组长度 - 1。
{
    int c[20];
    int i = 0, j = 0, k = 0;
    while (i <= m && j <= n)
	{
		if (a[i] <= b[j])
		{
			c[k++] = b[i++];
		}
		else
		{
			c[k++] = b[j++];
		}
	}
	while (i <= m)
	{
		c[k++] = a[i++];
	}
	while (j <= n)
	{
		c[k++] = b[j++];
	}
}

上述代码可以合并两个有序数组,而归并排序的思想就是将一个数组分成两个有序数组在合并为一个数组。 因为传递的参数是一个数组,我们需要对上面的Merge函数稍作改变。先建立两个新数组,再将目标数组分为两部分拷贝到新数组内,最后将两个新数组用上述方法合并到目标数组内

void Merge(int *arr, int left, int mid, int right)
{
	int *nums1 = MyCopy(arr, left, mid);        
	int *nums2 = MyCopy(arr, mid + 1, right);          //将数组的前后两部分拷贝到新数组内
        //MyCopy函数是我自己写的函数,将目标数组的一部分拷贝到新空间内,并返回空间地址(代码发在下面)
	int i = 0, j = 0;
	int k = left;

	while (i <= mid - left && j <= right - mid - 1)    
	{
                /*mid - left是nums1的长度减一,right - mid - 1是nums2的长度减一*/
		if (nums1[i] <= nums2[j])
		{
			arr[k++] = nums1[i++];
		}
		else
		{
			arr[k++] = nums2[j++];
		}
	}
	while (i <= mid - left)
	{
		arr[k++] = nums1[i++];
	}
	while (j <= right - mid - 1)
	{
		arr[k++] = nums2[j++];
	}                                     //将两个新数组合并到目标数组内

	free(nums1);      
	free(nums2);                     //释放空间
}

MyCopy函数

int* MyCopy(int *arr, int left, int right)
{
	int *nums;
	int i = left, j = 0;
	nums = (int*)malloc(sizeof(int) * (right - left + 1));
	for (; i <= right; i++)
	{
		nums[j] = arr[i];
		j++;
	}
	return nums;
}

如果要用上述方法,我们要保证数组的前半部分和后半部分分别有序。 这里我们可以继续将前半部分在拆为两部分,然后继续拆,一直拆到一个部分只有一个元素,此时必然有序,然后合并。 对后半部分,我们做同样处理。 这里我们使用递归实现。

void Merge_Sort(int *arr, int left, int right)
{
	if (left == right)
	{
		return;                   // 只有一个元素时返回
	}

	else
	{
		int mid = (left + right) / 2;
		Merge_Sort(arr, left, mid);      //对前半部分排序
		Merge_Sort(arr, mid + 1, right); //对后半部分排序
		Merge(arr, left, mid, right);    //合并
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值