Python实现归并排序

2023-11-20

Python实现归并排序

一、归并排序简介

归并排序(Merge Sort)是建立在归并操作上的一种效率很高的排序算法,比较占用内存。该算法是分治法(Divide and Conquer)的一个典型应用。

归并排序将两个或两个以上(一般是两个)有序的列表合并成一个新的有序列表。待排序列表是无序的,使用二分法递归地将列表最终拆分成只有一个元素的子表,只有一个元素的列表一定是有序的,此时递归往回合并,即可依次将待排序列表拆分然后合并成一个有序的列表。

二、归并排序原理

归并排序的原理如下:

1. 假设有两个已经有序的列表,设定两个指针分别指向这两个列表的起始元素,申请内存空间新建一个空列表,比较两个指针指向的元素大小,将较小的元素添加到新列表中,然后将该指针向该列表的下一个元素偏移,继续比较两个指针指向的元素和添加较小的到新列表中。直到其中一个列表的数据全部被添加完时,把另一个列表中剩下的数据按顺序添加到新列表中。这就实现了将两个有序列表合并成一个新的有序列表的方法。

2. 对待排序列表进行拆分,递归地拆分直到子列表中只有一个元素。

3. 只有一个元素的子列表一定是有序的,使用1中的方法对有序的子列表进行合并。第一次合并后新列表是有两个元素的有序列表,递归地往回合并,直到所有数据都合并到一个新的有序列表中,列表排序完成。

以列表 [10, 17, 50, 7, 30, 24, 27, 45, 15, 5, 36, 21] 进行升序排列为例。列表的初始状态如下图。

要进行升序排列,则合并两个有序子列表时,子列表也要是升序排列的,子列表只有一个元素时,先添加较小的数据到新列表中(降序反之)。

1. 先对待排序列表进行拆分,分成两个子列表,一般从 n/2 索引的位置进行拆分。例子中有12个元素,两个子列表都有6个元素。

2. 进行合并的前提是两个子列表都是有序的。待排序列表是无序的,第一次拆分后无法保证两个子列表都是有序的,所以继续对子列表进行拆分。左边的子表有6个元素,继续拆分成两个有3个元素的子表。

3. 现在的子表中有3个元素,还是无法保证一定有序,继续拆分。拆分后,一个子表只有1个元素,另一个子表有2个元素。

4. 对于只有1个元素的子表,它一定是有序的,直接返回,等待与它一起拆分出来的另一个子表有序时进行合并。

5. 对于有2个元素的子表,对它再进行一次拆分,分成两个都是只有1个元素的子表,然后进行合并,合并成有2个元素的有序列表。

6. 将上面有1个元素的子表和经过一次合并后有2个元素的有序列表进行合并,合并成有3个元素的有序列表。

7. 对同时拆分出来的另3个元素也进行相同的处理,递归拆分和合并成有3个元素的有序列表。

8. 两个有3个元素的子表都有序后,对它们进行合并,合并成有6个元素的有序列表。

9. 对同时拆分出来的另6个元素也进行相同的处理,递归拆分和合并成有6个元素的有序列表。

10. 两个有6个元素的子表都有序后,对它们进行合并,合并成最终的有序列表,列表排序完成。排序结果如下图。

三、Python实现归并排序

# coding=utf-8
def merge_sort(array):
    if len(array) == 1:
        return array
    left_array = merge_sort(array[:len(array)//2])
    right_array = merge_sort(array[len(array)//2:])
    return merge(left_array, right_array)


def merge(left_array, right_array):
    left_index, right_index, merge_array = 0, 0, list()
    while left_index < len(left_array) and right_index < len(right_array):
        if left_array[left_index] <= right_array[right_index]:
            merge_array.append(left_array[left_index])
            left_index += 1
        else:
            merge_array.append(right_array[right_index])
            right_index += 1
    merge_array = merge_array + left_array[left_index:] + right_array[right_index:]
    return merge_array


if __name__ == '__main__':
    array = [10, 17, 50, 7, 30, 24, 27, 45, 15, 5, 36, 21]
    print(merge_sort(array))

运行结果:

[5, 7, 10, 15, 17, 21, 24, 27, 30, 36, 45, 50]

在代码中,先实现了将两个有序列表进行合并的 merge(left_array, right_array) 函数。在该函数中,传入的两个列表(左表和右表)都是排好序的(升序或降序,上面代码中是升序)。先声明两个游标指针和一个新列表,两个指针一开始分别指向两个列表的起始位置,将两个指针指向的数据进行比较,然后将较小的数据添加到新列表中,被添加数据的指针向右移。当其中一个列表中的数据全部被添加到新列表中(指针再右移就会越界)时,此列表为空,停止移动和比较,此时,另一个列表中还剩若干个(1~n个)数据没有被添加到新列表中,继续按顺序将这些数据添加到新列表的尾部。

 实现归并排序函数merge_sort(array)时,递归调用merge(left_array, right_array)函数。在merge(left_array, right_array)函数对两个列表进行合并时,这两个列表必须都是有序的,而对待排序列表进行拆分时,无法保证两个子表一定是有序的,只有当被拆分的子表里只有一个元素时,这个子列表才一定是有序的。所以归并排序中递归地将待排序列表进行拆分,直到拆分成只有一个元素的列表,然后调用merge(left_array, right_array)函数进行合并,这样依次递归合并,最终实现归并排序。

四、归并排序的时间复杂度和稳定性

1. 时间复杂度

在归并排序中,不管待排序列表的初始状态如何,都不影响排序的时间复杂度。归并排序一直对待排序列表进行拆分,需要进行logn次拆分,在每一次递归合并中,需要进行n次比较和添加。时间复杂度为 T(n)=nlogn ,再乘每次操作的步骤数(常数,不影响大O记法),所以归并排序的时间复杂度为 O(nlogn) 。

对归并排序改进,可以在归并时先判断左表最大值与右表最小值的关系。如果左表的最大值小于等于右表的最小值,则说明待排序列表本身就是一段有序序列,不需要再归并,在待排序列表本身就有序的情况下,时间复杂度可以降至 O(n)。

2. 稳定性

在归并排序合并的过程中,如果有相等的数据,会先添加左表的数据到新列表中,再添加右表的数据,这不会改变相等数据的相对位置。所以归并排序是一种稳定的排序算法。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python实现归并排序 的相关文章

  • 八大排序算法-归并排序

    归并排序的定义 是将两个 或两个以上 有序表合并成一个新的有序表 即把待排序序列分为若干个子序列 每个子序列是有序的 然后再把有序子序列合并为整体有序序列 归并排序的基本思想 设r i n 由两个有序子表r i m 和r m 1 n 组成
  • 合并两个有序数组为一个有序数组

    一 归并排序 问题 两个有序数组 合并成一个有序数组 先依次比较两个数组 按照小的就传入新的数组 当这次比较完之后可能有一个数组的长度很长 留下一些数组 然后在新数组的末尾插入即可 两个有序数组的合并函数 int MergeList int
  • Python实现红黑树的删除操作

    Python实现红黑树的删除操作 本专栏的上一篇文章使用Python实现了红黑树的插入操作 参考 https blog csdn net weixin 43790276 article details 106456969 本篇文章使用Pyt
  • 求k个数组包含每个数组至少一个元素的最小范围(待字闺中,备忘)

    有k个有序的数组 请找到一个最小的数字范围 使得这k个有序数组中 每个数组都至少有一个数字在该范围中 例如 1 4 10 15 24 26 2 0 9 12 20 3 5 18 22 30 所得最小范围为 20 24 其中 20在2中 22
  • Python实现双端队列

    Python实现双端队列 关于双端队列的介绍 请参考 https blog csdn net weixin 43790276 article details 104033337 双端队列的数据存储结构可以是顺序表 也可以是链表 本篇文章使用
  • Python Tree库绘制多叉树的用法介绍

    Python Tree库绘制多叉树的用法介绍 Tree 库是一个 Python 的第三方库 这个库主要用于生成树和绘制树的图形 一 安装Tree pip install Tree 使用 Tree 库需要配合 PIL 库来实现绘图 二 官方案
  • 7--归并排序

    思想 将待排序序列分为两个子序列 再将两个子序列递归的继续分下去 直到序列有序 即序列中只有一个元素 再把所有有序子序列逐层合并为一个整体有序序列 每次合并是将两个有序表合并成一个有序表 图示 具体实现 把待排序序列分为两个子序列 然后让子
  • Python实现普通二叉树

    Python实现普通二叉树 二叉树是每个节点最多有两个子树的树结构 本文使用Python来实现普通的二叉树 关于二叉树的介绍 可以参考 https blog csdn net weixin 43790276 article details
  • 链表介绍

    链表介绍 链表与顺序表一样 也属于线性表 一个线性表是某类数据元素的一个集合 表里同时记录着元素之间的顺序关系 线性表的数据之间有顺序关系 顺序关系分为两种 一种是物理有序 即数据物理存储的位置顺序与数据之间的顺序关系一致 另一种是逻辑有序
  • Python二叉树的三种深度优先遍历

    Python二叉树的三种深度优先遍历 一 广度优先遍历和深度优先遍历 对二叉树进行遍历 traversal 是指依次对树中每个节点进行访问 在遍历的过程中实现需要的业务 对树的遍历方式有广度优先遍历和深度优先遍历两种方式 广度优先一般用队列
  • Python实现快速排序

    Python实现快速排序 一 快速排序简介 快速排序 Quick Sort 是一种效率很高的排序算法 是对冒泡排序的一种改进排序算法 快速排序首先任意选取一个数据 通常选待排序列表中的第一个数 作为基准数据 将待排序列表中的数据分割成独立的
  • 【模板】归并排序

    题目链接 https www luogu com cn problem P1177 1945年由约翰 冯 诺伊曼 John von Neumann 首次提出 如上图所示 归并排序的执行流程为 不断地将当前序列平均分割成 2 个子序列 直到不
  • 归并排序(递归,非递归)

    目录 写在前面的话 一 归并思想 二 归并排序递归实现 2 1思想实现 2 2排序实现 2 3代码实现 三 归并排序非递归实现 3 1思路实现 小区间优化 3 2边界值处理 3 2代码实现 写在前面的话 小伙伴们大家好啊 今天依旧小菜鸡库森
  • 栈和队列简介

    栈和队列简介 栈和队列是两种常用的数据结构 它们的数据是按线性结构存储的 因此 栈和队列也属于线性表 栈和队列的数据可以存储在一个顺序表里 也可以存储在一个链表里 只要满足线性存储结构就行 只对数据的线性结构有要求 对存储数据的具体结构并不
  • 排序算法6-归并排序

    1 什么是归并排序 归并排序是建立在归并操作上的一种有效的排序算法 该算法是采用分治法 Divide and Conquer 的一个非常典型的应用 将已有序的子 序列合并 得到完全有序的序列 即先使每个子序列有序 再使子序列段间有序 若将两
  • java七大排序——7_归并排序

    归并排序 将数组分为2块 再到每一小块再分为两块 直到最后一个元素为一块 然后进行有序数组合并 最终合并为一个有序数组 代码实现 public static void mergeSorts int array mergeSortsInter
  • 快速排序和归并排序的相同点和不同点(JAVA)

    首先我们贴出来快速排序的代码 public class QuickSort public int QuickSort int a int left int right int temp a left while left lt right
  • Python deque的用法介绍

    Python deque的用法介绍 deque 是Python标准库 collections 中的一个类 实现了两端都可以操作的队列 相当于双端队列 与Python的基本数据类型列表很相似 Python实现双端队列参考 https blog
  • Python实现归并排序

    Python实现归并排序 一 归并排序简介 归并排序 Merge Sort 是建立在归并操作上的一种效率很高的排序算法 比较占用内存 该算法是分治法 Divide and Conquer 的一个典型应用 归并排序将两个或两个以上 一般是两个
  • Python实现二叉搜索树的删除功能

    Python实现二叉搜索树的删除功能 二叉搜索树 二叉查找树 Binary Search Tree 又称为排序二叉树 有序二叉树 二叉搜索树的实现可以参考 https blog csdn net weixin 43790276 articl

随机推荐

  • 随手学习笔记

    1 正点原子zynq视频教程 真人版 P128 P132讲解ADDA 第30 1讲高速ADDA实验 ADC芯片简介 哔哩哔哩 bilibili 2 正点原子zynq视频教程 真人版 关于zynq FPGA讲解非常详细 可逐个详细学习 第1讲
  • 使用QZXing生成并解析二维码

    QZxing 是对 zxing 的一个封装 用于在 Qt 程序中加入条形码和二维码识别的功能 这里就讲讲如何编译和使用这个库 前几年 QZXing 的代码是放到 sourceforge net 上的 现在迁移到了 github com 所以
  • sql手工注入

    information schema 系统数据库 包含所有数据库相关信息 information schema schemata中schema name列 字段为所有数据库名称 information schema tables中table
  • 中山大学App校园地图功能分析

    中山大学App校园地图简单功能分析介绍 用户入口 进入中山大学App首页 即可看到校园地图 点击后进入校园地图主界面 校区选取 进入地图主界面后 即可呈现出校园地图 顶上正中间是选取校区的功能按钮 单击后出现全部4个校区可供选择 路线导航
  • 如何在手机上打开xmind文件_如何高效率整理电脑上的文件 ?

    个人电脑 01 没有时间整理 也不想整理 怎么办 1 1 只整理电脑桌面 电脑桌面放着各种文件 已经成为多数人的习惯 一打开电脑 就可以从电脑桌面上看见自己有哪些文件等着处理 当天处理的文件存放在桌面 第二天要用的时候 直接在桌面打开就可以
  • python遍历文件夹中的图片

    import cv2 import os mainFolder Images RectSmall myFolders os listdir mainFolder print myFolders for folder in myFolders
  • jre jdk更改目录后Java无法运行问题解决方案

    问题 在将Java文件 包含jdk jre 由C盘直接剪贴到D盘后 所有Java程序无法运行 且其Java图标不再显示 解决方案 首先更改环境变量 当我们单纯地将Java文件更改位置后 我们计算机的环境变量仍未改变 依旧是当时安装Java时
  • Verilog中if- else if语句和case语句用法:

    一 if语句 1 两种情况 if 条件语句 begin end else begin end 2 多种情况 if 条件语句 begin end else if 条件语句 begin end else if 条件语句 begin end el
  • 编程大师-Netty

    45 张图深度解析 Netty 架构与原理 里奥ii的博客 CSDN博客 netty全过程图解 最详细清晰版 netty流程 PANDA的博客 CSDN博客
  • Kafka学习(三)简单实例(可以简单做测试)

    java客户端连接kafka简单测试 本案例kafka版本是kafka 2 11 0 9 0 1 用java来实现kafka生产者 消费者的示例 在测试的过程中遇到的特别的问题以及解决办法 其他小问题就不一一列举了 1 使用kafka cl
  • libero-soc许可证申请和环境配置

    环境 64位机 在哪台电脑上安装libero soc 就用哪台电脑申请许可证 1 注册 https www microsemi co 在官网注册 之后申请的许可证会发到注册时填写的邮箱 2 申请许可证 https www microsemi
  • 操作系统 段页式存储管理

    一 引入 分页系统是以页面作为内存分配的基本单位 能有效地提高内存利用率 但信息共享等不方便 分段系统是以段作为内存分配的基本单位 它能够更好地满足用户多方面的需要 信息共享 动态链接等 但采用分区方式管理物理内存 仍然存在碎片问题 段页式
  • mysql varchar类型条件查询不加引号

    一张160w数据量的表 select from order promotion where order no 15441913435665186 select from order promotion where order no 1544
  • Gradle –多个启动脚本示例

    很少有build gradle示例向您展示如何创建多个启动脚本或可执行Java应用程序 1 单启动脚本 1 1在Gradle中 您可以使用应用程序插件来创建可执行的Java应用程序 build gradle apply plugin app
  • 蒙特卡洛积分、重要性采样、低差异序列

    渲染公式 渲染的目标在于计算周围环境的光线有多少从表面像素点反射到相机视口中 要计算总的反射光 每个入射方向的贡献 必须将他们在半球上相加 为入射光线 与法线 的夹角 为方便计算可以使用法线向量和入射向量 单位化 的乘积表示 对于基于图像的
  • 全国各省市座机电话区号整理

    excel数据整理下载地址 https download csdn net download MtiredM 87620876 json格式数据整理 const areaCodes 热门城市 010 北京市 024 沈阳市 0371 郑州市
  • Qt对话框

    Qt的对话框分为两种 模态对话框和非模态对话框 模态对话框 模态对话框 不可以对其其他窗口进行操作 比如像下面这种 出现后无法再操作其他窗口 比如像下面这种 创建后就无法在操作写代码的窗口 创建对话框要将 include
  • 【Unity&C#&随机数】随机数

    一个简单的随机数获得 0或1 使用了这样的代码 想要获得0或者1 if Input anyKeyDown float i 1 if i 1 i Random Range 0 Rang i i lt 0 5 0 1 Debug Log Cou
  • C语言经典100例题(18)--题目:求s=a+aa+aaa+aaaa+aa...a的值

    目录 题目 问题分析 代码 测试结果 题目 求s a aa aaa aaaa aa a的值 其中a是一个数字 例如2 22 222 2222 22222 此时共有5个数相加 几个数相加有键盘控制 问题分析 加数之间的规律 a a 0 10
  • Python实现归并排序

    Python实现归并排序 一 归并排序简介 归并排序 Merge Sort 是建立在归并操作上的一种效率很高的排序算法 比较占用内存 该算法是分治法 Divide and Conquer 的一个典型应用 归并排序将两个或两个以上 一般是两个