归并排序java代码实现

article/2025/11/7 0:58:47

归并排序,是一种分治算法。利用递归,将一个大的数据集合分解成小的子集合。将子集合排好序后,再合并起来。归并排序不是原地排序算法,因为它使用到了临时空间,这也是归并排序没有快速排序应用广泛的主要原因,虽然归并排序的时间复杂度,最好、最坏都是O(logn)。但是,这个也看使用场景,如果在空间换时间的场合,个人认为这种算法也有一定的用武之处。
我在网上找了一个动图,很直观。大家可以看一下。来源:https://www.cnblogs.com/fivestudy/p/10064969.html

在这里插入图片描述

下面看一下java的代码实现

public static void main(String[] args) {int[] arr = new int[]{10, 7, 8, 9, 1, 5};mergeSort(arr, arr.length);System.out.println(Arrays.toString(arr));}private static void mergeSort(int[] arr, int n) {mergeSortInternally(arr, 0, n - 1);}private static void mergeSortInternally(int[] arr, int p, int r) {if (p >= r) {return;}//find middle pointint q = p + (r - p) / 2;//递归分解数组元素下标,处理前半部分mergeSortInternally(arr, p, q);//处理后半部分mergeSortInternally(arr, q + 1, r);mergeBySentry(arr, p, q, r);}/*** 普通的合并算法*/private static void merge(int[] arr, int p, int q, int r) {//左半个数组的开始下标int i = p;//右半个数组的开始下标int j = q + 1;//临时数组的起始下标int k = 0;//初始化一个和当前分裂好的数组相同大小的临时数组int[] temp = new int[r - p + 1];while (i <= q && j <= r) {//比较左右两个数组的起始值,较小的元素放在临时数组的第一个位置if (arr[i] <= arr[j]) {temp[k++] = arr[i++];} else {temp[k++] = arr[j++];}}//分裂好的两个数组,很可能不是平均分配,所以可能会有一个数组先遍历完成,//另外一个数组还有未进行比较数据,此时直接将未进行比较的数组的数据添加到临时数组即可//初始化下标,先将下标初始化为左半部分的数组int start = i;int end = q;//说明右半部分未比较完,此时将下标再重置为右半部分的数组if (j <= r) {start = j;end = r;}//将未比较完的有序数组直接添加到临时数组中while (start <= end) {temp[k++] = arr[start++];}//将临时数组的数据拷贝到原数组中for (i = 0; i <= r - p; i++) {arr[p + i] = temp[i];}}/*** 添加了哨兵节点的合并算法** @param arr* @param p* @param q* @param r*/private static void mergeBySentry(int[] arr, int p, int q, int r) {//初始化左边数组对应的临时空间,增加一个哨兵节点的位置int[] leftArr = new int[q - p + 2];//初始化右边数组对应的临时空间,增加一个哨兵节点的位置int[] rightArr = new int[r - q + 1];//将原数组中,左边的数据拷贝到临时数组中for (int i = 0; i <= q - p; i++) {leftArr[i] = arr[p + i];}//左边数组增加哨兵节点leftArr[q - p + 1] = Integer.MAX_VALUE;//将原数组中,右边的数据拷贝到临时数组中for (int i = 0; i < r - q; i++) {rightArr[i] = arr[q + 1 + i];}//右边数组增加哨兵节点rightArr[r - q] = Integer.MAX_VALUE;int i = 0;int j = 0;int k = p;while (k <= r) {//左节点小于右节点时,将排好序的临时空间数据加入到原数组中,当i到达哨兵节点时,i不再增加,只增加j即可.if (leftArr[i] <= rightArr[j]) {arr[k++] = leftArr[i++];} else {arr[k++] = rightArr[j++];}}}

这里面的关键点是合并函数的实现逻辑,我贴出了2种合并函数的实现。
一种是:原始的合并实现,方法名是:merge
另一种是改良版本,增加了哨兵节点,方法名是:mergeBySentry
改良版本,明显更容易理解一点。在临界值的情况,大家注意使用哨兵节点,可以让代码逻辑更清晰。

上一篇快速排序java实现,我们聊了一下快速排序的实逻辑,这2种排序经常会在一起进行比较,大家觉着这2种实现逻辑有什么区别吗?最主要的区别是:
归并排序是先将大问题拆解成小问题,然后处理小问题,最后将小问题合并。
快速排序是先处理小的排序区间,然后慢慢处理大问题。
两种排序原理截然不同

(归并排序的代码主要来自于极客时间<数据结构与算法之美>的专栏,大家对算法感兴趣的,可以订阅一下这个专栏,专栏质量很高)

时间复杂度分析
极客的专栏里分析了这个过程,我直接抄过来,给大家看一下如何进行分析。想看全文的,可以移步专栏。
我们假设对 n 个元素进行归并排序需要的时间是 T(n),那分解成两个子数组排序的时间都是 T(n/2)。我们知道,merge() 函数合并两个有序子数组的时间复杂度是 O(n)。所以,套用前面的公式,归并排序的时间复杂度的计算公式就是:

T(1) = C;   n=1时,只需要常量级的执行时间,所以表示为CT(n) = 2*T(n/2) + n; n>1

通过这个公式,如何来求解 T(n) 呢?还不够直观?那我们再进一步分解一下计算过程:


T(n) = 2*T(n/2) + n= 2*(2*T(n/4) + n/2) + n = 4*T(n/4) + 2*n= 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n= 8*(2*T(n/16) + n/8) + 3*n = 16*T(n/16) + 4*n......= 2^k * T(n/2^k) + k * n......

通过这样一步一步分解推导,我们可以得到 T(n) = 2kT(n/2k)+kn。当 T(n/2^k)=T(1) 时,也就是 n/2^k=1,我们得到 k=log2n 。我们将 k 值代入上面的公式,得到 T(n)=Cn+nlog2n 。如果我们用大 O 标记法来表示的话,T(n) 就等于 O(nlogn)。所以归并排序的时间复杂度是 O(nlogn)
空间复杂度分析
递归代码的空间复杂度并不能像时间复杂度那样累加。原因是,尽管每次合并操作都需要申请额外的内存空间,但在合并完成之后,临时开辟的内存空间就被释放掉了。在任意时刻,CPU 只会有一个函数在执行,也就只会有一个临时的内存空间在使用。临时内存空间最大也不会超过 n 个数据的大小,所以空间复杂度是 O(n)。
原地排序算法分析
很明显,归并排序的空间复杂度不是O(1),所以不是原地排序算法。
稳定排序算法分析
归并排序稳不稳定,关键要看merge函数。我们每次都让a[p,q]的元素都先进入临时数组,a[q+1,r]的元素后进入临时数组,最后的结果就是稳定的。所以,归并排序就是稳定排序算法。


http://chatgpt.dhexx.cn/article/r4NdRFxE.shtml

相关文章

分治算法实现经典归并排序java实现

目录 1.什么是分治算法 分治法 基本思想 2.分治算法的体现:归并排序 归并排序 基本思想 3.代码实现 1.什么是分治算法 分治法 分治法&#xff0c;字面意思是“分而治之”&#xff0c;就是把一个复杂的1问题分成两个或多个相同或相似的子问题&#xff0c;再把子问题分成…

归并排序 Java实现 简单易懂

归并排序 归并排序采用的是分治(divide-and-conquer)法思想。 1.基本思想&#xff1a; 将待排序元素分成大小大致相同的2个子集合&#xff0c;分别对2个子集合进行排序&#xff0c;最终将排好序的子集合合并成为所要求的排好序的集合。 2.执行过程&#xff1a; 3.时间复杂度…

归并排序java版

归并排序java版 归并排序java版 归并排序java版 好长时间没写过归并排序&#xff0c;在学习并发中又遇到了一个归并排序的demo&#xff0c;于是就想试试自己还能不能写出来&#xff0c;结果没写出来…&#xff0c;看了一些文章后&#xff0c;整理了一下思路&#xff0c;把归并…

归并排序(Java)

归并排序 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列有序&a…

JAVA编程----归并排序

一、概念及其介绍 归并排序&#xff08;Merge sort&#xff09;是建立在归并操作上的一种有效、稳定的排序算法&#xff0c;该算法是采用分治法(Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每…

归并排序java(内附超详解图文讲解)

目录 归并排序介绍: 归并排序图解&#xff1a; 示意图1 示意图2 归并排序详细步骤&#xff1a; 1.组合 2.分组 完整代码 归并排序介绍: 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法&#xff0c;该算法采用经典的分治(divide- and-conquer)策略(分治法将问题分…

java实现归并排序(详解)

主要思想 归并排序和快速排序都是基于分而治之的算法思想。 归并排序先将待排序的数组不断拆分&#xff0c;直到拆分到区间里只剩下一个元素的时候。不能再拆分的时候。这个时候我们再想办法合并两个有序的数组&#xff0c;得到长度更长的有序数组。当前合并好的有序数组为下…

Launcher3--抽屉

抽屉是用来放置安卓手机中所有需要显示到Launcher上的(当然也可以进行过滤&#xff0c;将不想显示的隐藏起来)应用和小部件&#xff0c;启动应用、添加快捷方式到桌面、卸载等。之前也提到过&#xff0c;有些Launcher是没有抽屉的&#xff0c;如MIUI的Launcher。在Launcher3中&…

Android launcher3 开发初始篇

版本&#xff1a;1.0 日期&#xff1a;2014.8.26 2014.8.27 2014.11.10 版权&#xff1a;© 2014 kince 转载注明出处 好久没有写博客&#xff0c;也是因为工作比较忙的关系。当然这不是理由&#xff0c;主要是很多bug要改&#xff0c;而自己的效率又不是很高&#xff0c;…

安卓Launcher 简介

转载请注明出处&#xff1a;安卓Launcher 简介_安卓launcher是什么_Mr_Leixiansheng的博客-CSDN博客 文章概述&#xff1a; 1.什么是Launcher 2.新建一个Launcher工程 3.Apps去哪了 4.显示桌面背景 最近换了新工作(๑ㅁ)&#xff0c;又是要去接触新的知识了。闲话不多说&…

android12.0(S) Launcher3 细节修改

去除 Launcher3 底部类似 dockbar 条目 packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java availableHeightPx windowBounds.availableSize.y;mInfo info; - isTablet info.isTablet(windowBounds);//isTablet info.isTablet(windowBounds);is…

Launcher3

Android 4.4 (KK)开始Launcher默认使用Launcher3&#xff0c;Launcher3较Launcher2 UI 有部分调整&#xff0c;主要包括: &#xff08;1&#xff09; 状态栏透明&#xff0c;App List 透Wallpaper&#xff1b; &#xff08;2&#xff09; 增加overview模式&#xff0c;可以调整…

Launcher3 模块的简单设计

Launcher3 模块的简单设计 Lancher3 路劲&#xff1a; Z:\xxx\packages\apps\Launcher3 任务 1、AllApps背景透明化。 2、Allapps前3个图标变为Chrome、youtube、play商店。 3、长按桌面空白处在弹出的按钮下添加一个图标变大按钮&#xff0c;一个图标变小按钮&#xff0c;点…

android12.0(S) Launcher3 导入 AndroidStudio 调试编译

验证环境 aosp 12.0 源码&#xff0c;分支 android-12.0.0_r3 可以参考之前写的 android12.0(S) Pixel 3XL (QCOM 845) 编译刷机 AndroidStudio 版本 Android Studio Arctic Fox | 2020.3.1 Patch 4 gradle 版本 gradle-7.0.2-bin.zip gradle:7.0.4 二手 Pixel 3 XL一台可直…

launcher3的具体学习

目录结构&#xff1a; allapps 目录&#xff1a;主要存放主菜单界面相关代码。 anim目录&#xff1a;存放动画相关&#xff0c; badge目录&#xff1a;存放图标标识相关 compat目录&#xff1a;存放解决兼容性相关。 config目录&#xff1a;配置Launcher相关功能的宏开关 dragn…

Android10/11 原生Launcher3深度定制开发

一、引言 关于Android10和11系统Launcher3的定制有很多&#xff0c;根据项目的需求会进行各种定制开发&#xff0c; 于是就需要研究Launcher3的源码。本文主要从Android 11的Launcher3QuickStep着手 &#xff08;go版本或者其他版本类似&#xff09;从常用的修改进行分析&#…

Launcher3-桌面布局+主要的类+启动流程

一、launhcer3桌面布局二、launcher3主要的类LauncherModel&#xff1a;BubblTextView&#xff1a;DragController&#xff1a;LauncherAppState&#xff1a;DragView&#xff1a;DragSource&#xff0c;DropTarget&#xff1a;Folder&#xff1a;FolderIcon&#xff1a;Launch…

Launcher3--初识Launcher3

一、Launcher简介 Launcher时开机完成后第一个启动的应用&#xff0c;用来展示应用列表和快捷方式、小部件等。Launcher作为第一个(开机后第一个启动的应用)展示给用户的应用程序&#xff0c;其设计的好坏影响到用户的体验&#xff0c;甚至影响用户购机的判断。所以很多品牌厂商…

Android Launcher3分析及定制主题实现

一. Launcher3 简介 **launcher3是在Launcher2的基础上进化的版本,从Android 4.4 开始就使用Launcher3 .(kk版,kk2版)作为桌面使用,以前我们都在使用Launcher2,我们使用的是KK版本,具体区别后面再说. ** 1 Launcher3 桌面变成了动态管理,launcher2 里面默认最多加载五个worksp…

Android Launcher3简介

一.Launcher3概述 Launcher顾名思义&#xff0c;就是桌面的意思&#xff0c;也是android系统启动后第一个启动的应用程序&#xff0c;这里以android11为例&#xff0c;和其他应用并无区别&#xff0c;只是增加了对其他app和widget的管理窗口&#xff0c;且可以为用户定制化一些…