详解十大经典排序算法(五):归并排序(Merge Sort)

排序算法—sort(),stable_sort(),merge() 排序目录:一.sort()二.stable_sort()三.merge()1.merge函数的作用:2.为什么引入归并排序merge()函数3.代码4.例题P1309 瑞士轮 一.sort() cppreference中的详细解释 二.stable_sort() stable_sort()遇见大小相同的值不会改变他们的位置 cppreference中的详细解释 三.merge() cpprefer... 阅读详情

算法原理

归并排序的核心思想是将一个大的数组分割成多个小的子数组,然后分别对这些子数组进行排序,最后将排序后的子数组合并起来,得到一个有序的大数组。

算法描述

归并排序(Merge Sort)是一种经典的排序算法,其原理基于分治(Divide and Conquer)策略。它的核心思想是将一个大问题分割成多个小问题,解决小问题后再将它们合并以得到最终结果。

具体步骤如下:

  1. 分割(Divide):将待排序的数组递归地分割成两个子数组,直到每个子数组只包含一个元素。

  2. 排序(Conquer):对每个子数组进行排序,通常使用递归来排序。

  3. 合并(Merge):将排好序的子数组合并成一个新的有序数组。

  4. 重复步骤2和步骤3,直到整个数组都被排序。

动画演示

在这里插入图片描述

代码实现

 public static void mergeSort(int[] array) {
        if (array == null || array.length <= 1) {
            return; // 如果数组为空或只有一个元素,无需排序
        }
        int[] temp = new int[array.length]; // 创建一个临时数组来辅助排序
        mergeSort(array, 0, array.length - 1, temp); // 调用归并排序函数
    }

    private static void mergeSort(int[] array, int left, int right, int[] temp) {
        //直到每个子数组只包含一个元素 即:left == right
        //也就是说最小排序单位是长度为2的数组,当长度为2时,此时无法再递归,而进行排序
        if (left < right) {
            int mid = (left + right) / 2;
            // 对左半部分进行归并排序
            mergeSort(array, left, mid, temp);
            // 对右半部分进行归并排序
            mergeSort(array, mid + 1, right, temp);
            // 合并两个有序数组
            merge(array, left, mid, right, temp);
        }
    }

    private static void merge(int[] array, int left, int mid, int right, int[] temp) {
        int i = left; // 左数组的起始索引
        int j = mid + 1; // 右数组的起始索引
        int k = left; // 临时数组的起始索引

        // 比较左右两个数组的元素,将较小的元素放入临时数组
        while (i <= mid && j <= right) {
            if (array[i] <= array[j]) {
                temp[k++] = array[i++];
            } else {
                temp[k++] = array[j++];
            }
        }

        // 将左数组剩余部分复制到临时数组
        while (i <= mid) {
            temp[k++] = array[i++];
        }

        // 将右数组剩余部分复制到临时数组
        while (j <= right) {
            temp[k++] = array[j++];
        }

        // 将临时数组的元素复制回原数组
        for (i = left; i <= right; i++) {
            array[i] = temp[i];
        }
    }

算法复杂度

时间复杂度(最坏)时间复杂度(最好)时间复杂度(平均)空间复杂度稳定性
O(n log n)O(n log n)O(n log n)O(n)稳定
  • 平均时间复杂度为 O(n log n),其中 n 是待排序数组的大小。

  • 最好情况和最坏情况下的时间复杂度也都是 O(n log n)。

  • 归并排序需要额外的空间来存储临时数组,在最坏情况下需要与输入数组一样大的空间,因此空间复杂度是 O(n)。

归并排序的优化方式

上述代码实现了基本的归并排序算法,但它在合并过程中存在一个潜在的优化点。在归并排序的合并阶段,将左右两个有序数组合并为一个有序数组时,可以通过判断左边数组的最大值和右边数组的最小值来优化合并操作,避免不必要的比较。

这个优化点可以通过添加一个条件来判断是否需要合并,如果左边数组的最大值小于等于右边数组的最小值,则无需合并,因为两个数组已经是有序的,不需要进行额外的比较和移动。

private static void merge(int[] array, int left, int mid, int right, int[] temp) {
    int i = left; // 左数组的起始索引
    int j = mid + 1; // 右数组的起始索引
    int k = left; // 临时数组的起始索引

    // 如果左数组的最大值小于等于右数组的最小值,则无需合并,直接返回
    if (array[mid] <= array[j]) {
        return;
    }

    // 比较左右两个数组的元素,将较小的元素放入临时数组
    while (i <= mid && j <= right) {
        if (array[i] <= array[j]) {
            temp[k++] = array[i++];
        } else {
            temp[k++] = array[j++];
        }
    }

    // 将左数组剩余部分复制到临时数组
    while (i <= mid) {
        temp[k++] = array[i++];
    }

    // 将右数组剩余部分复制到临时数组
    while (j <= right) {
        temp[k++] = array[j++];
    }

    // 将临时数组的元素复制回原数组
    for (i = left; i <= right; i++) {
        array[i] = temp[i];
    }
}

这个优化逻辑在判断左右两个子数组已经有序时,可以避免不必要的比较和赋值操作,提升归并排序的性能。

归并排序核心就是 递归,分治,记住这两个词就能大致理解这个算法,递归思想真的很重要,不容易完全理解,还得继续练习-_-


相关概念
• 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
• 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
• 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
• 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

使用C#详解常用排序算法(三):归并排序(Merge Sort) 结合C#代码讲解归并排序。 阅读详情

相关推荐

C/C++ Merge Sort排序算法详解及源码

Merge Sort(归并排序)是一种经典的分治排序算法,它将一个待排序的数组分成两个子数组,分别对子数组进行排序,然后再将排好序的子数组进行合并,从而得到最终的有序数组。

希望我的博客,能帮上你解决学习中工作中所遇到的问题 7897

11.6 归并排序

合并阶段”从底至顶地将左子数组和右子数组合并为一个有序数组。需要注意的是,从长度为 1 的子数组开始合并,合并阶段中的每个子数组都是有序的。是一种基于分治策略的排序算法,包含图 11-10 所示的“划分”和“合并”阶段。如图 11-11 所示,“划分阶段”从顶至底递归地将数组从中点切分为两个子数组。具体实现细节比较复杂,有兴趣的读者可以查阅相关资料进行学习。观察发现,归并排序与二叉树后序遍历的递归顺序是一致的。对于链表,归并排序相较于其他排序算法具有显著优势,归并排序的实现如以下代码所示。

让学习成为一种习惯 1242

基于C++的Merge Sort分治排序算法实战详解

当数据无法全部加载进内存时(如 TB 级日志文件),Merge Sort 成为核心组件。流程如下:分批读取固定大小的数据块内存中排序后写回临时文件执行多路归并,逐段读取各文件头部,输出有序结果此方法广泛应用于数据库引擎、搜索引擎索引构建等系统。

weixin_36382073的博客 1123

排序算法 - 归并排序详解

基本介绍 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。 基本思想 将序列中待排序数字分为若干组,最终每个数字分为一组。(默认长度为1的序列是有序的) 将若干个组两两合并,保证合并后的组是有序的。(俩个子序列头部进行比较大小) 重复第二步操作直到只剩下一组,排序完成。 归并排序思想示

张大安的博客 4931

merge sort 算法的C++实现

merge sort 排序 C++ merge sort 算法的C++实现

Merge Sort 算法 C语言实现

Merge Sort 算法的C语言实现 linux 下编译;windows下没试过,也许需要改头文件

一文读懂『归并排序』算法(Merge Sort)

归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用 分治法(Divide and Conquer) 的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

专注自动化、性能测试、测试架构学习交流 6712

合并排序算法——merge sort

#include <stdio.h> #include <malloc.h> #include <limits.h> void init(int A[],int p,int r);//初始化数组 void print_A(int A[],int p,int r);//打印数组元素 void merge(int A[],int p,int q,int r);//合并排序算法 /************合并排序算法的实现******************/ int main() { int p,q,r; printf("合并排序算法的实现:\n"); printf("请输入p、q、r的值(输入格式1,12,13):"); scanf("%d,%d,%d",&p,&q,&r); printf("p=%d,q=%d,r=%d\n",p,q,r); int * A = (int*)malloc((r+1)*sizeof(int)); init(A,p,r); printf("待合并数组:\n"); print_A(A,p,r); printf("\n\n"); printf("合并排序算法的实现过程:\n"); merge(A,p,q,r); free(A);//释放动态数组空间 return 0; }

归并排序

归并排序 “归并”的含义是将两个或者两个以上的有序表组合成一个新的有序表。假设待排序表含有n个记录,则可以看成n个有序的子表,每个子表长度为1,然后两两归并,得到 n/2 个长度为2或者1的有序表;再两两归并,直到合并成一个长度为n的有序表为止,这种排序方法称为 2-路归并排序。 递归的2-路归并排序算法是基于分治算法的 ,以O(NlogN)最坏情形时间运行,而所使用的比较次数几乎是最优的...

一个小白的成长之路 4908

mergesort

基于c++的归并排序算法。排序算法大体可分为两种:     一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。     另一种是非比较排序,时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等。

速腾聚创多激光雷达点云采集,并用RVIZ进行显示

在ubuntu20.04系统下,使用速腾聚创官方提供的软件RSView,对激光雷达的默认IP地址、MSOP 包端口号、 DIFOP包端口号和时间模式等配置进行查看和修改。使用交换机对两个激光雷达进行组网,实现多激光雷达数据采集,并用RVIZ同时显示两个雷达点云。使用wireshark对比两个雷达数据包。

abanchao的博客 5888

图解排序算法及实现——归并排序 (Merge Sort)

思路 归并排序(MergeSort),是创建在归并操作上的一种有效的排序算法,效率为O(nlogn) 。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。 实现 递归法: 自顶向下(Top-Down) 直接在原序列上直接归并排序,每次归并排序分别对左右两边进行归并排序,直至细分到两两分组。 ...

张渊猛的博客 4万+

F280049C_HRPWM_死区时间高精度控制与MEP技术实战解析

本文深入解析了F280049C的HRPWM模块及其基于MEP技术的死区时间高精度控制。通过实测数据与TI官方代码对比,详细阐述了DBREDHR和DBFEDHR寄存器的配置技巧、精度优化方法及常见问题调试,为电源管理和电机控制应用提供了实用的实战指南。

yolo5detector的博客 216

排序——归并排序(Merge sort)

1945年,约翰·冯·诺依曼(John von Neumann)发明了归并排序,这是典型的分治算法的应用。 定义 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。 算法思路 归并排序算法有两个基本的操作,...

努力中的老周的专栏 18万+

哨兵2植被参数反演避坑指南:SNAP中10m/20m分辨率选择与缺失波段处理

本文深入解析了使用SNAP软件进行哨兵2号植被参数反演时的关键操作与决策。核心在于理解SNAP生物物理处理器NNET10m与NNET20m的架构差异,根据是否需要反演冠层叶绿素含量(Cab)等参数,明智选择10米或20米分辨率工作流。文章详细指导了大气校正、波段重采样及处理L2A数据中B01波段“缺失”等常见问题的解决方案,为生态监测与精准农业应用提供清晰的避坑指南和完整实战流程。

wdx01234567的博客 261

Jetson-nano 编译实时内核并烧录

前言 之前一篇文章介绍了正常的烧录过程,使用的是默认内核,实际工作中需要对内核打补丁升级为实时内核,并对其重编译。 一、准备内容 官网大法好 官方内核下载链接 官方交叉编译器下载链接 官方文档 ubuntu主机一台 根据官网选择下载对应的文件, 1、L4TDriver Package (BSP) source jetson内核文件。 2、官方交叉编译器 因为我们不是在jetson上直接编译,而jetson是arm平台,所以要进行交叉编译。 二、使用步骤 1.解压 内核 tar -xjf public_s

ldl371122的博客 3286

十大经典排序算法之归并排序(Merge Sort)

归并排序(Merge Sort) 1945年由约翰·冯·诺伊曼(John von Neumann)首次提出 执行流程 ①、不断地将当前序列平均分割成2个子序列 ✓ 直到不能再分割(序列中只剩1个元素) ②、不断地将2个子序列合并成一个有序序列 ✓ 直到最终只剩下1个有序序列 (1)归并排序 — divide实现 @Override protected void sort() { leftArray = (T[]) new Comparable[array.length >> 1];

派拉斯兔子的博客 4191

银河麒麟服务器(ky10 server)arm、x86安装qemu虚拟机

接下来就可以新建服务器了。

zengliguang的专栏 8709

十大排序算法之归并排序

归并排序 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。 算法步骤 不断地将当前序列平均分割成2个子序列,直到不能再分割(序列中只剩1个元素) 不断地将2个子序列合并成一个有序序列,直到最终只剩下1个有序序列 divide实现 private E[] leftArray;

morris 1万+

抓包抖音充值页面实现微信支付宝充值抖币,可提供api

抓包抖音充值接口教程,实现微信支付宝充值抖币收款通道

eeeee1212的博客 1万+

【Bug已解决】Codex CLI 运行时出现 command not found: codex 解决方案

方案适用场景推荐指数修复 PATH 配置最常见的基础排查方向⭐⭐⭐⭐⭐检查原生二进制完整性PATH 正常但执行仍然异常⭐⭐⭐⭐统一包管理器混用多种包管理器导致混乱⭐⭐⭐⭐确认安装脚本未被跳过CI/CD 或企业策略环境⭐⭐⭐⭐排查网络下载渠道企业内网/受限网络环境⭐⭐⭐需要留意 warning 中是否涉及脚本执行失败、网络超时重试等信息,这类 warning 往往是后续问题的前兆,建议出现明显的下载/网络相关警告时就主动重新安装一次确认。Codex CLI 报。

一键难忘的博客 1万+

十大经典排序算法——归并排序(Merge Sort)

文章目录算法代码1-递归代码2-非递归 参考的文章: (1)这或许是东半球讲十大排序算法最好的一篇文章 (2)排序算法 - 面试中的排序算法总结 (3)必学十大经典排序算法,看这篇就够了 算法 (1)归并排序的核心思想是分治,分而治之,将一个大问题分解成无数的小问题进行处理,处理之后再合并,这里我们采用递归来实现; (2)时间复杂度O(nlogn) 代码1-递归 /** *...

Heorin X的博客 517

1.1 了解Spring框架 -《SSM深入解析与项目实战》

文章目录第1篇 基础概念第1章 谈谈SSM框架和Redis1.1 了解Spring框架1.1.1 如何学习Spring1.1.2 IoC(Inversion of Control 控制反转)1.1.3 AOP(Aspect Oriented Programing面向切面编程) 项目中所有的源码都可以在此链接的仓库中找到:https://github.com/chenhaoxiang/uifuture-ssm 本章非常形象的介绍了Springn中最核心的两个概念,IoC和AOP,使用了现实中的例子

谙忆-陈浩翔 2133

归并排序(MERGE-SORT)

归并排序(MERGE-SORT) 1.基本介绍 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。 2.归并排序思想示意图 1、基本思想: 可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程 2、

xiaoshiguang3的博客 762

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【内部排序】八:归并排序(Merge Sort)详解与代码

归并排序是多次将两个或两个以上的有序表合并成一个新的有序表。最简单的归并是直接将两个有序的子表合并成一个有序的表。   2-路归并排序 在内部排序中,通常采用的是2-路归并排序。即:将含有n个元素的序列看成是n个有序的子序列,每个子序列的长度为1,而后两两合并,得到n/2个长度为2或1的有序子序列,再进行两两合并。。。直到最后由两个有序的子序列合并成为一个长度为n的有序序列。2-路归并的核心操

牧之 4347

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Thrust排序算法完全指南:radix sort、merge sort与stable sort对比

Thrust是NVIDIA推出的C++并行算法库,提供了高效的GPU加速排序功能。在Thrust中,**radix sort(基数排序)**、**merge sort(归并排序)** 和 **stable sort(稳定排序)** 是最核心的三种排序算法,每种都有其独特的优势和应用场景。 ## 📊 三种排序算法核心特点对比 ### Radix Sort(基数排序) **radix sort*

gitblog_00949的博客 783

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

上一篇: 详解十大经典排序算法(四):希尔排序(Shell Sort)
下一篇: 详解十大经典排序算法(六):快速排序(QuickSort)
_蓝橙
博客等级 码龄7年 1179粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值