归并排序算法

给定你一个长度为 n的整数数列。

请你使用归并排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

输入格式

输入共两行,第一行包含整数 n。

第二行包含 n个整数(所有整数均在 1∼1091∼109 范围内),表示整个数列。

输出格式

输出共一行,包含 n个整数,表示排好序的数列。

数据范围

1≤n≤100000

输入样例:

5
3 1 2 4 5

输出样例:

1 2 3 4 5

代码如下:

java 复制代码
package com.zy.Acwing.mergeSort;
import java.util.Scanner;
//本段代码主要实现了归并排序算法
public class P787 {
	static int N = 100010;
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		int n = scan.nextInt();
		int[] arr = new int[N];
		for(int i = 0 ; i < n ; i++) {
			arr[i] = scan.nextInt();
		}
		merge_sort(arr,0,n-1);
		for(int i = 0 ; i < n ; i++) {
			System.out.print(arr[i]+" ");
		}
	}
	public static void merge_sort(int[] arr,int left,int right) {
		if(left>=right)  return;
		int mid = left + right >> 1;
		merge_sort(arr,left,mid);
		merge_sort(arr,mid + 1,right);
		int k = 0,i = left,j = mid+1;
		int[] temp = new int[right-left+1];
		while(i <= mid && j <= right) {
			if(arr[i] <= arr[j])   temp[k++] = arr[i++];
			else temp[k++] = arr[j++];
		}
		while(i <= mid) temp[k++] = arr[i++];
		while(j <=right) temp[k++] = arr[j++];
		for(i = left,k = 0;i <= right;i++,k++) arr[i] = temp[k];
	}
	

}

自己基于目前的了解对此段代码进行一些解释:

  • **if(left>=right) return; 递归结束的条件,**当数组中只有一个数或者达到left>=right条件时,直接结束递归;
  • **int mid = left + right >> 1;**取整个数组的分隔线,向上取整,使整个数组一分为二;
  • merge_sort(arr,left,mid); merge_sort(arr,mid + 1,right);

使用递归思想,使用mid作为分隔线,划分为arr[left,....mid]和arr[mid+1,....right]两个数组;

递归之后的两个数组都是有序的,下面的代码就是在两个有序数组中,归并为一个大的有序数组;

  • int k = 0,i = left,j = mid+1; int[] temp = new int[right-left+1];

定义一个temp数组,用来存放排序之后的元素,

i为一个数组的左边界,j为另一段数组的左边界(前面已经提到一个数组被分割为两个数组)

java 复制代码
while(i <= mid && j <= right) {
	if(arr[i] <= arr[j])   temp[k++] = arr[i++];
	else temp[k++] = arr[j++];
}

本段代码首两个数组的元素都没有比较完,如果其中一个已将全部比较完成,另一组没有,则本循环结束,较小的放进temp,同时下标向右移,较大的留下继续比较;

java 复制代码
while(i <= mid) temp[k++] = arr[i++];
while(j <=right) temp[k++] = arr[j++];

本段代码实现的功能是如果其中一个数组已将全部比较完成,另一组没有还剩下的元素,把剩下的元素((剩下的元素都是有序的,无须再次比较)放进temp中;

  • for(i = left,k = 0;i <= right;i++,k++) arr[i] = temp[k];

将temp中排好序的元素放到arr中;

  • 为什么不用 mid - 1 作为分隔线呢?

即 merge_sort(q, l, mid - 1 ), merge_sort(q, mid, r)

因为 mid = l + r >> 1 是向下取整,mid 有可能取到 l (数组只有两个数时),造成无限划分

解决办法: mid 向上取整就可以了, 即 mid = l + r + 1 >> 1;

  • 为什么进行递归之后,两段数组变为有序的呢?

首先要明白归并算法的整个流程是什么的,B站中有一个动画展示的比较清楚,地址如下:归并算法动画演示https://www.bilibili.com/video/BV1Je4y1K7Qd/?spm_id_from=333.999.top_right_bar_window_custom_collection.content.click&vd_source=f83925eb71a2ec1683580bbf22db27ec 通过递归的不断执行,当划分为n个数组时,一个数组只有一个元素,一个数本身就是有序的,满足l==j的条件,无需执行后面的代码,结束最后一次的递归代码的执行;接着实现倒数第二次的递归,此时的数组元素是由两个元素组成,通过后面代码的比较,将这个含有两个元素的数组进行排序,完成之后,接着实现倒数第三次的递归,此时的数组元素是由四个元素组成,将这个含有两个元素的数组进行排序......,知道第一次递归结束,此时一个数组中的n个元素是有序的,排序完成;

其实,整个递归执行过程是一棵二叉树,先会递归到整棵树的底部,底部只有一个节点一定有序,然后在回溯时不断合并相邻两个区间,每次合并之后都会将合并之后的区间排好序。那么当合并到根节点时,整个区间就有序了。

相关推荐
Java与Android技术栈1 分钟前
图像编辑器 Monica 之 CV 常见算法的快速调参
算法
别NULL14 分钟前
机试题——最小矩阵宽度
c++·算法·矩阵
珊瑚里的鱼14 分钟前
【单链表算法实战】解锁数据结构核心谜题——环形链表
数据结构·学习·程序人生·算法·leetcode·链表·visual studio
无限码力18 分钟前
[矩阵扩散]
数据结构·算法·华为od·笔试真题·华为od e卷真题
gentle_ice19 分钟前
leetcode——矩阵置零(java)
java·算法·leetcode·矩阵
查理零世20 分钟前
保姆级讲解 python之zip()方法实现矩阵行列转置
python·算法·矩阵
zhbi9840 分钟前
测量校准原理
算法
时间很奇妙!1 小时前
decison tree 决策树
算法·决策树·机器学习
sysu632 小时前
95.不同的二叉搜索树Ⅱ python
开发语言·数据结构·python·算法·leetcode·面试·深度优先
红鲤鱼遇绿鲤鱼2 小时前
uva 1354 Mobile Computing
算法