热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

排序算法专题归并排序

归并排序是一种十分经典的冲破O(n2)时间复杂度的排序算法,该算法是基于分治的思想,讲解算法原理之前,先看一下下面这张图。图片来源&#x

  归并排序是一种十分经典的冲破O(n2)时间复杂度的排序算法,该算法是基于分治的思想,讲解算法原理之前,先看一下下面这张图。
在这里插入图片描述


  • 图片来源:【算法】排序算法之归并排序
      上图就是归并算法的一个简单示例。该算法就是每次将数组递归拆解为两部分,直到所有部分包含元素为1,之后递归的将各个部分进行归并。
  • 具体的算法步骤如下:
  • 1:递归拆解数组,直到每个区块包含元素数量为1
    2:归并数组,直到归并后的数组长度等于原数组长度
    3: 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
    4:设定两个指针,最初位置分别为两个已经排序序列的起始位置
    5:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
    5:重复步骤 4直到某一指针达到序列尾
    7:将另一序列剩下的所有元素直接复制到合并序列尾
    8:重复步骤2-7

  从上述可以看出,该算法的实现是基于递归思想,但是所有的递归都可以转换成迭代,因此该算法有两个实现方式,递归和迭代。


  • 代码如下,以递归为例:
  • 如果单从原理原理上来直接写代码会比较复杂,我们可以将该算法拆解为两个部分,及分割和归并。分割是一个简单的递归,代码如下:

def mergeSort(nums):"""将输入数组递归拆分&#xff0c;直到长度为1时返回&#xff0c;对每一步返回的left,right进行顺序归并>>>mergeSort(3,38, 5, 44, 15, 36)>>>[3, 5, 15, 36, 38, 44]"""if len(nums) < 2:return numsmid &#61; len(nums)//2left, right &#61; nums[:mid], nums[mid:]return mergeHelp(mergeSort(left), mergeSort(right))

  • 其中mergeHelp是mergeSort的一个help方法&#xff0c;用于对拆分后的数组进行顺序归并。
  • 以[3,38, 5, 44, 15, 36]举个栗子&#xff0c;说一下递归过程&#xff1a;
  • 1&#xff1a;[3, 38, 5] [44, 15, 36]
    2&#xff1a;[3] [38, 5]
    3&#xff1a;[38] [5]
    4&#xff1a;[44] [15, 36]
    5&#xff1a;[15] [36]

  • 接下来我们实现mergeHelp方法&#xff0c;就是给定两个有序数组&#xff0c;将其按顺序合并为一个数组&#xff0c;代码如下&#xff1a;

def mergeHelp(left, right):"""归并排序的help方法&#xff0c;用于将拆分的left和right进行顺序归并>>>mergeHelp([1, 3, 5], [2, 4, 5]):>>>[1, 2, 3, 4, 5, 5]"""res &#61; []while left and right:if left[0] <&#61; right[0]:res.append(left.pop(0))else:res.append(right.pop(0))while left:res.append(left.pop(0))while right:res.append(right.pop(0))return res

  • 当我们实现了这个方法之后&#xff0c;看一下分割&#43;归并的过程
  • [3, 38, 5] [44, 15, 36]  第一次分割
    左数组[3, 38, 5]部分&#xff1a;
    [3] [38, 5]  第一次分割
    [38] [5]  第二次分割&#xff08;左数组分割完毕&#xff0c;所有部分元素均为1&#xff09;
    [5, 38]  第一次归并
    [3, 5, 38]emsp; 第二次归并&#xff0c;完成[3, 38, 5]部分序列的排序
    右数组[44, 15, 36]部分&#xff1a;
    [44] [15, 36]  第一次分割
    [15] [36]  第二次分割
    [15, 36]  第一次合并
    [15, 36, 44]  第二次合并
    原数组的所有子序列完成排序&#xff0c;进行最终的合并
    [3, 5, 15, 36, 38, 44]  排序完成

  • 算法解析&#xff1a;算法的时间复杂度从两个部分分来来看&#xff0c;很明显在mergeSort()递归方法里面&#xff0c;迭代公式为mid &#61; len(nums)//2&#xff0c;该方法的时间复杂度是O(log n)&#xff0c;而在mergeHelp()归并方法里面&#xff0c;每一步像res里面追加一下元素&#xff0c;最终的的运行次数为len(left)&#43;len(right)&#xff0c;很明显时间复杂度为O(n)&#xff0c;因此归并排序算法的总时间复杂度为O(n log n)。由于算法运行过程中&#xff0c;会递归生成原数组的切片&#xff0c;切片总长度为n&#xff0c;所以归并排序算法的空间复杂度为O(n)。
  • 注意到我们在进行归并操作是&#xff0c;使用的是如下代码

while left and right:if left[0] <&#61; right[0]:res.append(left.pop(0))else:res.append(right.pop(0))

  • 也就是说对于同样大小的元素&#xff0c;我们先插入位于左边的&#xff0c;而后插入右边的&#xff0c;因此归并排序不会改变相同元素的相对位置&#xff0c;因此该算法是稳定的。

推荐阅读
  • 由二叉树到贪心算法
    二叉树很重要树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。单就面试而言,在 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • Go语言实现经典排序算法:归并排序
    本文介绍如何使用Go语言实现经典的归并排序算法,探讨其原理、代码实现及性能特点。适合Golang开发者和编程爱好者。 ... [详细]
  • 本文探讨了如何使用自增和自减运算符遍历二维数组中的元素。通过实例详细解释了指针与二维数组结合使用的正确方法,并解答了常见的错误用法。 ... [详细]
  • 给定行数 numRows,生成帕斯卡三角形的前 numRows 行。例如,当 numRows 为 5 时,返回的结果应为:[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]。 ... [详细]
  • 利用决策树预测NBA比赛胜负的Python数据挖掘实践
    本文通过使用2013-14赛季NBA赛程与结果数据集以及2013年NBA排名数据,结合《Python数据挖掘入门与实践》一书中的方法,展示如何应用决策树算法进行比赛胜负预测。我们将详细讲解数据预处理、特征工程及模型评估等关键步骤。 ... [详细]
  • 本题探讨了在大数据结构背景下,如何通过整体二分和CDQ分治等高级算法优化处理复杂的时间序列问题。题目设定包括节点数量、查询次数和权重限制,并详细分析了解决方案中的关键步骤。 ... [详细]
  • 本文详细介绍了福昕软件公司开发的Foxit PDF SDK ActiveX控件(版本5.20),并提供了关于其在64位Windows 7系统和Visual Studio 2013环境下的使用方法。该控件文件名为FoxitPDFSDKActiveX520_Std_x64.ocx,适用于集成PDF功能到应用程序中。 ... [详细]
  • JavaScript 中创建对象的多种方法
    本文详细介绍了 JavaScript 中创建对象的几种常见方式,包括对象字面量、构造函数和 Object.create 方法,并提供了示例代码和属性描述符的解释。 ... [详细]
  • 本次挑战涉及数组截断操作,初看似乎简单,但实际上考察了对数组切片方法的理解与应用。本文将详细解析该算法的实现逻辑,并提供多个示例以加深理解。 ... [详细]
  • 如何使用Ping命令来测试网络连接?当网卡安装和有关参数配置完成后,可以使用ping命令来测试一下网络是否连接成功。以winXP为例1、打开XP下DOS窗口具体操作是点击“开始”菜 ... [详细]
  • 优化网页加载速度:JavaScript 实现图片延迟加载
    本文介绍如何使用 JavaScript 实现图片延迟加载,从而显著提升网页的加载速度和用户体验。 ... [详细]
  • 版本控制工具——Git常用操作(下)
    本文由云+社区发表作者:工程师小熊摘要:上一集我们一起入门学习了git的基本概念和git常用的操作,包括提交和同步代码、使用分支、出现代码冲突的解决办法、紧急保存现场和恢复 ... [详细]
  • 本文将详细介绍如何利用PHP语言实现根据特定字段(如日期)横向合并两个数组的方法。通过具体示例,我们将展示如何有效地处理数据,以满足实际应用中的需求。 ... [详细]
author-avatar
天若无雨666
这个菇凉很宅,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有