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

算法原理

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

算法描述

归并排序(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的函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/220464.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Azure Machine Learning - 在 Azure 门户中创建演示应用

目录 准备环境启动向导配置搜索结果添加自动提示功能添加建议创建、下载和执行清理资源 使用 Azure 门户的“创建演示应用”向导来生成可下载的“localhost”样式的 Web 应用&#xff0c;该应用在浏览器中运行。 根据其配置&#xff0c;生成的应用在首次使用时就能正常运行&…

第2章 知识抽取:概述、方法

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

信号可靠性剖析

问题 基于信号发送的进程间通信方式可靠吗&#xff1f;&#xff1f;&#xff1f; 信号查看(kill -l) 信号的分类 不可靠信号 (传统信号) 信号值在 [1, 31] 之间的所有信号 可靠信号 (实时信号) 信号值在 [SIGRTMIN&#xff0c;SIGRTMAX]&#xff0c;即&#xff1a;[34&…

odoo自定义提示性校验

背景: 在odoo16的原生的代码里&#xff0c;可以给按钮添加一个 confirm属性&#xff0c;从而达到 提示性校验的效果。 问题&#xff1a; 这个属性加了之后一定会弹出提示性校验的对话框&#xff0c;于是如何根据我们的实际业务&#xff0c;从后端返回提示性信息&#xff0c;…

2023-12-05 Qt学习总结 (AI辅助) 未完待续

点击 <C 语言编程核心突破> 快速C语言入门 Qt学习总结 前言一 Qt是什么二 Qt开发工具链三 Qt编程涉及的术语和名词四 Qt Creator使用五 hello Qt!六 Qt控件和事件七 Qt信号和槽八 Qt自定义信号和槽九 Qt QObject基类十 QWidget基类十一 QMainWindow基类十二 QLabel文本框…

SL6015B降压恒流60V耐压1.5A高辉调光LED芯片 电路简单 元器件少

SL6015B是一款专为LED照明应用设计的降压恒流芯片&#xff0c;具有60V的耐压能力&#xff0c;最大输出电流可达1.5A。它采用高辉调光方式&#xff0c;通过改变输入电压或电流来调节LED的亮度。此外&#xff0c;SL6015B还具有电路简单和元器件数量少的特点&#xff0c;使其成为一…

Dinky之安装部署与基本使用

Dinky之安装部署与基本使用 Dinky概览Linux安装部署解压到指定目录初始化MySQL数据库修改配置文件加载依赖启动Dinky Docker部署启动dinky-mysql-server镜像启动dinky-standalone-server镜像 Dinky的基本使用上传jar包Flink配置集群管理集群实例管理集群配置管理 创建作业语句编…

clickhouse的向量化执行

背景 clickhouse快的很大一部分原因来源于数据的向量化执行&#xff0c;本文就来看一下向量化执行和正常标量执行的区别 SIMD的向量化执行 从上图可知&#xff0c;clickhouse通过SIMD指令可以做到一个cpu周期操作两个向量的运算操作&#xff0c;比起普通的cpu指令效率提高了N…

第17章 匿名函数

第17.1节 匿名函数的基本语法 [捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 { // 函数体 }语法规则&#xff1a;lambda表达式可以看成是一般函数的函数名被略去&#xff0c;返回值使用了一个 -> 的形式表示。唯一与普通函数不同的是增加了“捕获列表”。 …

读书笔记-《数据结构与算法》-摘要3[选择排序]

选择排序 核心&#xff1a;不断地选择剩余元素中的最小者。 找到数组中最小元素并将其和数组第一个元素交换位置。在剩下的元素中找到最小元素并将其与数组第二个元素交换&#xff0c;直至整个数组排序。 性质&#xff1a; 比较次数(N-1)(N-2)(N-3)…21~N^2/2交换次数N运行…

【Redis】Redis 的学习教程(十三)Redis 各场景

由于Redis 支持比较丰富的数据结构&#xff0c;因此他能实现的功能并不仅限于缓存&#xff0c;而是可以运用到各种业务场景中&#xff0c;开发出既简洁、又高效的系统 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-bo…

P=NP?

背景&#xff1a;   2000年5月24日&#xff0c;新罕布什尔州的克莱数学研究所列出了数学和计算机科学中七个未解决的问题。然而&#xff0c;直到今天&#xff0c;这些问题中只有一个被解决了&#xff0c;那就是庞加莱猜想&#xff08;Poincar Conjecture&#xff09;——被俄…

上下拉电阻会增强驱动能力吗?

最近看到一个关于上下拉电阻的问题&#xff0c;发现不少人认为上下拉电阻能够增强驱动能力。随后跟几个朋友讨论了一下&#xff0c;大家一致认为不存在上下拉电阻增强驱动能力这回事&#xff0c;因为除了OC输出这类特殊结构外&#xff0c;上下拉电阻就是负载&#xff0c;只会减…

7.Vue UI库

7.Vue UI库 7.1移动端常用的UI库 &#xff08;1&#xff09; Vant&#xff1a;Vant 4 - A lightweight, customizable Vue UI library for mobile web apps.A lightweight, customizable Vue UI library for mobile web apps.https://vant-ui.github.io/vant/#/zh-CN &#xf…

ssm的网上奶茶店系统(有报告)。Javaee项目。

演示视频&#xff1a; ssm的网上奶茶店系统&#xff08;有报告&#xff09;。Javaee项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMvc Mybat…

【Linux】ubuntu配置SSH服务

要在Ubuntu上配置SSH服务&#xff0c;首先安装ssh-server sudo apt install openssh-server 安装完成后&#xff0c;可以检查一下是否安装成功 systemctl status ssh vim /etc/ssh/sshd_config 此时ubuntu就可以被远程连接工具连接了&#xff0c;如果我们想配置关于SCP服务允…

elementUI table树默认箭头修改

table默认的箭头 需要的效果实心的 ::v-deep .el-icon-arrow-right {color: #49c0ff; }::v-deep.el-table .el-table__expand-icon {.el-icon-arrow-right:before {content: "\e791";} } content: "\e791"; 代表图标,可以在elementUI F12检查中得到

【c】16进制数转化为10进制数(计算方法在最后,大家也可以上网搜索视频,视频更详细,谢谢)

#include<stdio.h> #include<math.h> void trans(char arr1[],int arr[],int n) {puts("请输入16进制的数");for(int i0;i<n;i){scanf("%c",&arr1[i]);arr[i](int)arr1[i];}for(int k0;k<n;k){if(arr[k]>65&&arr[k]<7…

【C++】const关键字的详解!!

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

HPV专家谭巍主任谈:我国HPV感染率问题,以及该如何预防?

我国HPV感染问题比较严重&#xff0c;很多人在不知不觉中被感染。据统计&#xff0c;我国每年新增的HPV感染病例数量庞大&#xff0c;而感染人群的年龄也越来越年轻化。那么&#xff0c;我国的HPV感染率是多少?又该如何预防呢?对此北京劲松HPV诊疗中心主任谭巍曾做过临床调研…