归并排序算法

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

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

相关推荐
阿史大杯茶37 分钟前
Codeforces Round 976 (Div. 2 ABCDE题)视频讲解
数据结构·c++·算法
LluckyYH1 小时前
代码随想录Day 58|拓扑排序、dijkstra算法精讲,题目:软件构建、参加科学大会
算法·深度优先·动态规划·软件构建·图论·dfs
转调1 小时前
每日一练:地下城游戏
开发语言·c++·算法·leetcode
不穿格子衬衫2 小时前
常用排序算法(下)
c语言·开发语言·数据结构·算法·排序算法·八大排序
wdxylb2 小时前
使用C++的OpenSSL 库实现 AES 加密和解密文件
开发语言·c++·算法
aqua35357423582 小时前
蓝桥杯-财务管理
java·c语言·数据结构·算法
CV金科2 小时前
蓝桥杯—STM32G431RBT6(IIC通信--EEPROM(AT24C02)存储器进行通信)
stm32·单片机·嵌入式硬件·算法·蓝桥杯
sewinger2 小时前
区间合并算法详解
算法
XY.散人2 小时前
初识算法 · 滑动窗口(1)
算法
韬. .3 小时前
树和二叉树知识点大全及相关题目练习【数据结构】
数据结构·学习·算法