八大排序算法之五:归并排序

算法思想
归并的思想

归并排序(merge-sort)是利用归并的思想实现的排序算法,该方法采用经典的分治(divide-and-conquer)策略:分治法将问题分(divide)成一些小的问题,然后递归求解。而治(conquer)的阶段则将分的阶段得到的各答案“修补”在一起。
=>即:分而治之。

实现要点

归并算法的实现,分为两个过程:分、合

  1. “分”的过程:
    =>也就是实现递归调用的过程。
    1)确定递归的终止条件:
    left >= right
    只有待划分序列的左侧索引 left ,小于右侧索引 right时,才能保证待划分序列有1个以上的元素。也就才有递归划分的必要。
  2. 合并的过程的思路是这样的:
    ------主要分为3大步,进行相应的操作:
    1、在arr[]中,定义相应的下标l=left、r=middle+1,开始对arr进行遍历,遍历的条件是:l<=middle && r<=right。
    =>即:对左右序列同时进行遍历,依次取出其中较小的元素,并将该值存入到temp临时数组中去。直到左右序列中至少有一个已经被遍历完
    2、将没有遍历完的序列中,剩下的元素,按照顺序,填充到temp临时数组中去(因为既然是由上一步的归并操作得到的序列,那么,在该序列内部一定是有序的)
    3、将temp临时数组中的元素,copy到arr[]中的对应区域内。
    =>需要注意的是:并不是每次都将整个的temp临时数组中的元素都copy到arr[]中!每次实际上,只拷贝本次合并的元素!!!
  3. 因为归并的思想是:分治的思想----先分后治
    =>所以,在实现的时候,采用的是:
    对于一段待排序序列,先实现左右递归,进行划分,然后再实现对于该段序列的“合并”(也就是对该段序列排序的过程)。
算法实现

1、合并的过程

//合并的过程
	/**
	 * 
	 * @param arr 需要进行归并排序的数组
	 * @param left 合并的序列的最左侧元素的下标
	 * @param middle 合并的序列的中间值:middle = (left + right)/2
	 * @param right 合并的序列的最右侧元素的下标
	 * @param temp 合并过程中,用到的临时数组
	 */
	public static void merge(int[] arr,int left,int middle,int right,int[] temp) {
		int l = left;//左边序列的起始下标
		int r = middle + 1;//右边序列的起始下标
		int t = 0;//临时数组temp[]的索引,temp[]每次都是从下标为0处开始存储(方便)
		
		//1、在arr[]中,定义相应的下标l=left、r=middle+1,开始对arr进行遍历,遍历的条件是:l<=middle && r<=right。
		while(l<=middle && r<=right) {
			if(arr[l] < arr[r]) {
				//如果l对应的元素小,将它加入到temp[]中去
				temp[t] = arr[l];
				t += 1;
				l +=1;
			}else {
				//r对应的元素小,或与l对应的元素相等
				temp[t] = arr[r];
				t += 1;
				r += 1;
			}
		}
		
		//2、将没有遍历完的序列中,剩下的元素,按照顺序,填充到temp临时数组中去
		while (l<=middle) {
			//左边序列没有遍历完
			temp[t] = arr[l];
			t += 1;
			l += 1;
		}
		while(r<=right) {
			//右边的序列没有遍历完
			temp[t] = arr[r];
			t += 1;
			r += 1;
		}
		
		//3、将temp临时数组中的元素,copy到arr[]中的对应区域内
		/*
		 * 将元素copy回去的时候,可以依据arr[]中元素的下标,
		 * 进行合并操作的下标的总范围,所包含的元素个数,就是需要从temp[]向arr[]中copy的元素个数
		 */
		t = 0;
		while(left <= right) {
			arr[left] = temp[t];
			left += 1;
			t += 1;
		}
	}

2、划分的过程(在划分结束之后,调用 合并的过程)

//分+调用“合”的过程
	/**
	 * 这是实现递归调用(对应“分”)的方法
	 * @param arr 需要进行归并排序的数组
	 * @param left 先进行递归划分,再在递归之后进行合并操作 的范围的左侧边界索引
	 * @param right 右侧边界索引
	 * @param temp 临时数组,用于 合并的过程
	 */
	public static void divide(int[] arr,int left,int right,int[] temp) {
		//进行递归的条件
		if(left < right) {
			
			int middle = (left + right) / 2;
			// 向左递归
			divide(arr, left, middle, temp);
			// 向右递归
			divide(arr, middle + 1, right, temp);

			// 进行“合并”的过程
			merge(arr, left, middle, right, temp);
		}
		
		
	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值