热门标签 | 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;因此该算法是稳定的。

推荐阅读
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 深入理解C++中的KMP算法:高效字符串匹配的利器
    本文详细介绍C++中实现KMP算法的方法,探讨其在字符串匹配问题上的优势。通过对比暴力匹配(BF)算法,展示KMP算法如何利用前缀表优化匹配过程,显著提升效率。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 开发笔记:9.八大排序
    开发笔记:9.八大排序 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
  • 在给定的数组中,除了一个数字外,其他所有数字都是相同的。任务是找到这个唯一的不同数字。例如,findUniq([1, 1, 1, 2, 1, 1]) 返回 2,findUniq([0, 0, 0.55, 0, 0]) 返回 0.55。 ... [详细]
  • 本文探讨了卷积神经网络(CNN)中感受野的概念及其与锚框(anchor box)的关系。感受野定义了特征图上每个像素点对应的输入图像区域大小,而锚框则是在每个像素中心生成的多个不同尺寸和宽高比的边界框。两者在目标检测任务中起到关键作用。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 从零开始构建完整手机站:Vue CLI 3 实战指南(第一部分)
    本系列教程将引导您使用 Vue CLI 3 构建一个功能齐全的移动应用。我们将深入探讨项目中涉及的每一个知识点,并确保这些内容与实际工作中的需求紧密结合。 ... [详细]
  • 帝国CMS多图上传插件详解及使用指南
    本文介绍了一款用于帝国CMS的多图上传插件,该插件通过Flash技术实现批量图片上传功能,显著提升了多图上传效率。文章详细说明了插件的安装、配置和使用方法。 ... [详细]
  • 本文详细介绍了 React 中的两个重要 Hook 函数:useState 和 useEffect。通过具体示例,解释了如何使用它们来管理组件状态和处理副作用。 ... [详细]
  • 汇编语言等号伪指令解析:探究其陡峭的学习曲线
    汇编语言以其独特的特性和复杂的语法结构,一直被认为是编程领域中学习难度较高的语言之一。本文将探讨汇编语言中的等号伪指令及其对初学者带来的挑战,并结合社区反馈分析其学习曲线。 ... [详细]
  • 本文介绍如何使用 Python 的 xlrd 库读取 Excel 文件,并将其数据处理后存储到数据库中。通过实际案例,详细讲解了文件路径、合并单元格处理等常见问题。 ... [详细]
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社区 版权所有