当前位置: 首页 > news >正文

【数据结构与算法】十大经典排序算法-归并排序

🌟个人博客:www.hellocode.top
🏰Java知识导航:Java-Navigate
🔥CSDN:HelloCode.
🌞知乎:HelloCode
🌴掘金:HelloCode
⚡如有问题,欢迎指正,一起学习~~


当谈到高效的排序算法时,归并排序是一个备受推崇的选择。归并排序是一种分治算法,它将一个大问题分解成若干个小问题,然后逐个解决这些小问题,并将它们合并成一个整体的解。

基本思想

这里采用五分钟学算法大佬的图解,十分清晰

  1. 分解阶段: 将待排序数组分成两个相等或近似相等的子数组,不断将问题规模缩小。
  2. 解决阶段: 递归地对两个子数组进行排序,直到子数组的长度为1(即已有序)。
  3. 合并阶段: 将排好序的子数组合并成一个有序的数组,这是归并排序的核心操作。

三个阶段,涉及到递归就比较难理解(个人感觉),最好配合动画好好理解理解。主要就是分解和归并(将大问题分解为小问题,再通过归并过程合并并排序)

代码实现

每次随便写数组挺麻烦的,后续就都使用我写的工具类来生成随机数组了~

归并排序相对难理解一些,主要涉及到分解和归并,将待排序数组一个个拆分,直到拆分为1个1组(无需排序),接下来就是自底向上逐个合并,在合并的同时进行排序操作,最终合并好的就是有序的数组了

/*** @author HelloCode* @blog https://www.hellocode.top* @date 2023年08月15日 19:33*/
public class MergeSort {public static void main(String[] args) {// 生成容量为15的由100以内随机数构成的int数组(用到了自己写的一个工具类)int[] arr = ArrayUtil.randomIntArray(15, 100);System.out.println("原数组:" + Arrays.toString(arr));mergeSort(arr);System.out.println("排序后:" + Arrays.toString(arr));}private static void mergeSort(int[] arr) {if (arr == null || arr.length <= 1) {return; // 数组为空或只有一个元素,无需排序}// 创建临时数组(避免多次创建)int[] temp = new int[arr.length];// 递归入口sort(arr, temp, 0, arr.length - 1);}// 拆分private static void sort(int[] arr, int[] temp, int left, int right) {// 递归出口if (left >= right) {return;}// 记录中间值(左边数组的末尾,+1为右边数组的起始)int mid = left + ((right - left) >> 1);// 开始拆分sort(arr, temp, left, mid);sort(arr, temp, mid + 1, right);// 归并merge(arr, temp, left, mid, right);}// 归并(排序)private static void merge(int[] arr, int[] temp, int left, int mid, int right) {// 记录临时数组索引int p = left;// 左半边起始索引int i = left;// 右半边起始索引int j = mid + 1;// 开始归并// 两边都还有的情况while(i <= mid && j <= right){if(arr[i] <= arr[j]){temp[p++] = arr[i++];}else{temp[p++] = arr[j++];}}// 左边还有剩余的情况(直接加到临时数组末尾)while(i <= mid){temp[p++] = arr[i++];}// 右边还有剩余的情况(直接加到临时数组末尾)while(j <= right){temp[p++] = arr[j++];}// 将临时数组拷贝回原数组for(int k = left; k <= right; k++){arr[k] = temp[k];}}
}

测试:

原数组:[83, 49, 19, 75, 26, 64, 59, 60, 11, 97, 36, 41, 17, 31, 69]
排序后:[11, 17, 19, 26, 31, 36, 41, 49, 59, 60, 64, 69, 75, 83, 97]

生成随机数组的工具类:

/*** @author HelloCode* @blog https://www.hellocode.top* @date 2023年08月13日 20:01*/
public class ArrayUtil {private static final Random RANDOM = new Random();public static int[] randomIntArray(int capacity,int max){// 创建capacity大小的数组(1~max)int[] res = new int[capacity];for(int i = 0; i < capacity; i++){res[i] = RANDOM.nextInt(max) + 1;}return res;}
}

优化

归并排序本身是一个稳定且效率较高的排序算法,但还是有一些优化方法可以进一步提升性能:

  1. 插入排序优化: 对于小规模子数组,使用插入排序可以提高性能。当子数组长度小于一定阈值时,切换到插入排序可以减少递归调用开销。
  2. 自底向上归并: 在归并阶段,可以使用自底向上的方法,避免递归调用,从而减少栈空间的使用。
  3. 优化合并操作: 在合并阶段,如果左子数组的最大元素小于右子数组的最小元素,可以直接跳过合并操作,因为两个子数组已经有序。

总结

优点

  1. 归并排序稳定且适用于各种数据类型。
  2. 具有稳定的时间复杂度O(n log n),适用于大规模数据排序。
  3. 分治思想使其易于理解和实现,同时也为优化提供了空间。

缺点

  1. 归并排序需要额外的存储空间来存储临时数组,空间复杂度较高。
  2. 在小规模数据排序时,性能稍逊于快速排序。

复杂度

  • 时间复杂度:平均情况、最好情况和最坏情况下的时间复杂度均为O(n log n)。
  • 空间复杂度:空间复杂度为O(n),需要额外的存储空间来存储临时数组。

使用场景

  • 归并排序适用于需要稳定排序的场景,对性能有一定要求。
  • 特别适合用于外部排序,如在磁盘上对大文件进行排序。

通过分治思想,归并排序将排序问题分解为小问题,并通过合并操作将它们逐步解决,从而实现高效且稳定的排序。这使得归并排序成为计算机科学中重要的算法之一。

http://www.lryc.cn/news/130752.html

相关文章:

  • 基于深度学习创建-表情符号--附源码
  • .netcore grpc的proto文件字段详解
  • 带你了解建堆的时间复杂度
  • 人工智能原理(6)
  • 单片机模块化编程文件创建流程
  • docker image
  • 力扣75——单调栈
  • Webpack和Parcel详解
  • linux系统服务学习(六)FTP服务学习
  • 7.原 型
  • 【图像分类】理论篇(2)经典卷积神经网络 Lenet~Resenet
  • C++系列-内存模型
  • [管理与领导-30]:IT基层管理者 - 人的管理 - 向上管理,管理好你的上司,职业发展事半功倍。什么样的上司不值得跟随?
  • Java进阶篇--迭代器模式
  • 【CAM】CAM(Class Activation Mapping)——可视化CNN的特征定位
  • Maven教程_编程入门自学教程_菜鸟教程-免费教程分享
  • Gof23设计模式之模板方法模式
  • springBoot 配置文件 spring.resources.add-mappings 参数的作用
  • 《Java极简设计模式》第03章:工厂方法模式(FactoryMethod)
  • C++11并发与多线程笔记(11) std::atomic续谈、std::async深入谈
  • React快速入门
  • windows权限维持—SSPHOOKDSRMSIDhistorySkeletonKey
  • CSS 两栏布局和三栏布局的实现
  • 消息中间件相关面试题
  • 成集云 | 电子签署集成腾讯云企业网盘 | 解决方案
  • 提升大数据技能,不再颓废!这6家学习网站是你的利器!
  • uniapp开发小程序-有分类和列表时,进入页面默认选中第一个分类
  • 小程序-uni-app:hbuildx uni-app 安装 uni-icons 及使用
  • PHP中in_array()函数用法详解
  • 热电联产在综合能源系统中的选址定容研究(matlab代码)