归并排序算法

给定你一个长度为 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个元素是有序的,排序完成;

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

相关推荐
此生只爱蛋5 分钟前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
blammmp13 分钟前
Java:数据结构-枚举
java·开发语言·数据结构
昂子的博客35 分钟前
基础数据结构——队列(链表实现)
数据结构
咕咕吖37 分钟前
对称二叉树(力扣101)
算法·leetcode·职场和发展
九圣残炎1 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu1 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!2 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚2 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
为什么这亚子3 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
3 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习