排序算法--归并排序的两种方法

归并排序是用分治思想,分治模式在每一层递归上有三个步骤:

分解(Divide):将n个元素分成个含n/2个元素的子序列。
解决(Conquer):用合并排序法对两个子序列递归的排序。
合并(Combine):合并两个已排序的子序列已得到排序结果。

归并排序时间复杂度O(nlogn),每次归并处理n个,归并logn次。
归并排序空间复杂度O(n),其实是长度n的临时数组和logn的压入栈的数据,默认就是O(n)了。

排序动画参考

用递归实现:

private void MergeSort(int[] arr, int[] tempArr, int start, int end)
{
	if(start >= end)
		return;

	// 求出中间的索引
	int mid = ((end - start) >> 1) + 1;
	// 区分左边和右边
	int start1 = start, 	end1 = mid;
	int start2 = mid + 1, 	end2 = end;

	// (先分解)对左边进行归并, 对右边进行归并
	MergeSort(arr, tempArr, start1, end1);
	MergeSort(arr, tempArr, start2, end2);

	// 循环比较两部分的头,小的先入临时数组,直到一方全部入完 
	//(递归的最深层,左右两部分都是一个元素,相当于start1 = end1 start2 = end2)
	// (从最深层开始往上归并,元素数量开始合并,且按序排列完成)
	int k = start;
	while(start1 <= end1 && start2 <= end2)
		tempArr[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];

	// 只剩下1部分了,全部移到临时数组后面
	while(start1 <= end1)
		tempArr[k++] = arr[start1++];

	// 只剩下2部分了,全部移到临时数组后面
	while(start2 <= end2)
		tempArr[k++] = arr[start2++];

	//将临时数组 完成排序的部分 替换到原数组上
	for(k = start; k <= end; k++)
	{
		arr[k] = tempArr[k];
	}
}

void mergeSort(int[] arr, int len) {
    int[] seg = new int[len];
    MergeSort(arr, seg, 0, len - 1);
}

用迭代实现:
思路:第一层for循环控制步长,第二层循环对每个排序单元进行排序。
为了方便理解,举一个例子:
假设有一个长度为10的数组要处理

for (int seg = 1; seg < len; seg += seg) 
{
	// seg = 1,2,4,8
    for (int start = 0; start < len; start += seg + seg) 
    {
    	//seg = 1, start = 0,2,4,6,8  0-2,2-4,4-6,6-8,8-10之间的分两组先排
    	//seg = 2, start = 0,4,8	0-4,4-8,8-10之间的分两组排
    	//seg = 4, start = 0,8		0-8,8-10之间的分两组排
    	//seg = 8, start = 0        0-10之间的分两组排
    }
}

实现

private void MergeSort(int[] arr, int len)
{
	int[] tempArr = new int[len];

	// 步长控制分解长度, 分组处理
	for(int seg = 1; seg < len; seg += seg)
	{
		// 按照步长,依次处理步长单元内的排序
		for(int start = 0; start < len; start += seg + seg)
		{
			// 确定每个步长单元内的起始位,中间位,结尾位
			int low = start, mid = Math.Min(start + seg, len), high = Math.Min(start + seg + seg, len);
			int k = low;
			// 人为将步长内的元素分成两组,进行排序
			//(最开始的轮次, 两组内的元素个数都是1, 随着循环轮次增加,组内元素越来越多,归并的过程)
			int start1 = low, end1 = mid;
			int start2 = mid, end2 = high;

			// 循环比较两组的头,小的先入临时数组,直到一方全部入完 
			// 这里判断不能用=, 因为high 可能会越界
			while(start1 < end1 && start2 < end2)
				tempArr[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
			
			while(start1 < end1)
				tempArr[k++] = arr[start1++];

			while(start2 < end2)
				tempArr[k++] = arr[start2++];
				
		}

		// 将排好序的数组替换到原数组上,继续循环
		int[] temp = arr;
		arr = tempArr;
		tempArr = temp;
	}
}

void mergeSort(int[] arr, int len) {
    MergeSort(arr, len);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值