python实现归并排序

news2024/10/7 14:33:15

归并排序

归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,拍好各数组的顺序,再合并数组。

将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。

归并排序示意图

在这里插入图片描述

python代码实现-递归版

# 归并排序
def merge_sort(num_list):
    length = len(num_list)
    print(num_list)
    # 递归终止退出条件
    if length <= 1:
        return num_list
    # 拆分
    mid = length // 2  # /2 普通除法,结果为浮点数 //2 整除
    # 对左侧的列表进行排序   1.递归中,左侧数据拆分完才执行下面的
    left_l = merge_sort(num_list[:mid])
    # 对右侧的列表进行排序  2.递归中,右侧数据拆分完才执行下面的
    right_l = merge_sort(num_list[mid:])
    print("left_l:{},right_l:{}".format(left_l, right_l))
    # 3.递归中,上面拆分完了才执行这下面的代码。最初都拆成了一个元素
    # merge 合并操作
    # 初始化两个指针p, q 初始位置为起始位置,初始化一个临时数组temp_list
    p, q, temp_list = 0, 0, list()
    # 计算当前被合并的列表的长度
    len_left, len_right = len(left_l), len(right_l)
    # 对左右两个数组进行排序,用临时数组存储  //p q指针的使用前提是left_l 和right_l是有序的
    while len_left > p and len_right > q:
        if left_l[p] <= right_l[q]:
            temp_list.append(left_l[p])
            p += 1
        else:
            temp_list.append(right_l[q])
            q += 1
    # 如果left 和 right_l 的长度不相等( len_left > p and len_right > q才排序,q、p达到一方的长度后就停止了,会有一方长的没排),
    temp_list += left_l[p:]
    temp_list += right_l[q:]
    # 把长的部分直接追加到列表中

    return temp_list


if __name__ == '__main__':
    num_list = [6, 5, 3, 1, 8, 7, 2, 4]
    new_list = merge_sort(num_list)
    print('num_list:', new_list)


代码分析

执行过程:

(控制台输出) 先拆分完最左边的->再排完最左边的->再拆分完最右边的->再排完最右边的->左右合并排完最后的
[6, 5, 3, 1, 8, 7, 2, 4]
[6, 5, 3, 1]
[6, 5]
[6]
[5]
left_l:[6],right_l:[5]
[3, 1]
[3]
[1]
left_l:[3],right_l:[1]
left_l:[5, 6],right_l:[1, 3]
[8, 7, 2, 4]
[8, 7]
[8]
[7]
left_l:[8],right_l:[7]
[2, 4]
[2]
[4]
left_l:[2],right_l:[4]
left_l:[7, 8],right_l:[2, 4]
left_l:[1, 3, 5, 6],right_l:[2, 4, 7, 8]
num_list: [1, 2, 3, 4, 5, 6, 7, 8]

执行步骤

第一步:拆分,除2除2不断的二分。分到不能分后开始排序。拆分过程如上。(所以递归层数为:log(底数2)(指数n))
第二步:排序,设定两个指针,最初位置分别为两个已经排序(重点)序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
第四步:重复第三步直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾,完成一轮排序

时间复杂度

拆分的过程中不断二分,因此递归层数为:log(底数2)(指数n)
每层循环大约为:n次
时间复杂度为:O(nlogn)

非递归版

def merge_sort(num_list):
    length = len(num_list)
    if length <= 1:
        return num_list

    # 使用循环代替递归
    step = 1 # 从1开始 不断×2和递归版拆分相反
    while step < length:
        left = 0
        while left < length - step:
            print("left:{}".format(left))
            mid = left + step
            right = min(left + 2 * step, length)
            temp_list = merge(num_list[left:mid], num_list[mid:right])
            num_list[left:left + len(temp_list)] = temp_list  # 将归并排序中合并得到的有序列表 temp_list 更新到原始列表 num_list 的相应位置。
            left += 2 * step
        step *= 2
        print("step:{}".format(step))
    return num_list


def merge(left_list, right_list):
    p, q, temp_list = 0, 0, list()

    while p < len(left_list) and q < len(right_list):
        if left_list[p] <= right_list[q]:
            temp_list.append(left_list[p])
            p += 1
        else:
            temp_list.append(right_list[q])
            q += 1

    temp_list += left_list[p:]
    temp_list += right_list[q:]

    return temp_list


if __name__ == '__main__':
    num_list = [6, 5, 3, 1, 8, 7, 2, 4]
    new_list = merge_sort(num_list)
    print('num_list:', new_list)

在归并排序的循环实现中,stepleftmidright 是循环中的一些变量,它们有以下含义:

  1. step(步长):

    • step 是归并排序中的步长,它表示每次迭代中子数组的大小。循环的外部使用 while step < length 来不断增加步长,直到步长超过列表长度。
  2. left(左指针):

    • left 是指向当前子数组的起始位置的指针。在循环内,left 的值随着每次子数组合并而增加。
  3. mid(中间指针):

    • mid 是当前子数组的中间位置的指针。在归并排序中,每次合并两个有序子数组时,mid 用于确定左右两个子数组的边界。
  4. right(右指针):

    • right 是指向当前子数组的结束位置的指针。在循环内,right 的值随着每次子数组合并而增加。

下面是循环中涉及这些变量的核心代码:

step = 1
while step < length:
    left = 0
    while left < length - step:
        mid = left + step
        right = min(left + 2 * step, length)
        temp_list = merge(num_list[left:mid], num_list[mid:right])
        num_list[left:left + len(temp_list)] = temp_list
        left += 2 * step
    step *= 2

在外循环中,step 不断翻倍,内循环中,left 指向当前子数组的起始位置,mid 指向中间位置,right 指向结束位置。temp_list 存储合并后的有序子数组,然后通过切片操作将其更新到原始列表 num_list 中的相应位置。随着循环的进行,left 不断增加,表示下一个子数组的起始位置,直到整个列表有序。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

银行常用操作指引:浦发

文章目录 引言浦发2.1 设置查询密码2.2 微信公众号绑定2.3 查询卡转账额度II 其他银行常用操作see also引言 浦发 2.1 设置查询密码 2.2 微信公众号绑定 入口:点击菜单的微信通知 用途:查询余额和明细 口令:解除绑定 2.3 查询卡转账额度 II 其他银行常用操作

06 栈

目录 1.栈 2.实现 3.OJ题 1. 栈 1. 栈的概念和结构 栈: 这一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&…

OSS存储引擎如何使用以及如何添加图片【建议收藏】

Aliyun OSS对象存储&#xff0c;可以用来做文件服务器&#xff0c;存放一些文件&#xff0c;图片等资源&#xff0c;那么我们使用OSS&#xff0c;需要经历以下步骤&#xff1a; 这里就从如何开通OSS服务开始进行&#xff0c;到如何上传一个资源文件到OSS结束。 1、阿里云注册 …

最新AI系统ChatGPT网站系统源码,支持AI绘画,GPT语音对话,ChatFile文档对话总结,DALL-E3文生图,MJ绘画局部编辑重绘

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GPT…

Python中==和is有什么区别

是比较两个对象的内容是否相等&#xff0c;即两个对象的“值”是否相等&#xff0c;不管两者在内存中的引用地址是否一样。 is 比较的是两个实例对象是不是完全相同&#xff0c;它们是不是同一个对象&#xff0c;占用的内存地址是否相同。即is比较两个条件&#xff1a;1.内容相…

LeetCode670.最大交换

我真的怀疑他是不是难度等级评错了&#xff0c;因为感觉没到中级&#xff0c;总之先看题吧 给定一个非负整数&#xff0c;你至多可以交换一次数字中的任意两位。返回你能得到的最大值。 示例 1 : 输入: 2736 输出: 7236 解释: 交换数字2和数字7。示例 2 : 输入: 9973 输出:…

数字拆分--完全背包问题

一、题目 https://acm.ecnu.edu.cn/problem/3034/ 二、思路 本来算法就很弱&#xff0c;加上很久没刷题&#xff0c;做这道题真的是一言难尽~ 一开始我以为是找规律写递推式&#xff0c;写到f(9)的时候就觉得不对劲&#xff0c;又想了一会&#xff0c;还是没想到&#xff0…

【Linux配置yum源以及基本yum指令】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、yum是什么&#xff1f; 二、什么是软件包&#xff1f; 三、三种安装软件包的方式 四、yum的相关操作 4.1、搜索软件 4.2、安装软件 4.3、卸载软件 4.4、那…

Python | 七、栈 Stack、队列 Queue

栈的基础知识 是一种数据结构&#xff0c;在Python中常使用列表来模拟实现特点&#xff1a;先进后出 栈的基本操作 因为Python中通过列表模拟实现栈&#xff0c;所以以下的基本操作实际是列表的一些操作获取长度&#xff0c;使用len(stack)方法进栈&#xff0c;使用stack.app…

Element组件完整引入、按需引入、样式修改(全局、局部)、简单安装less以及npm命令证书过期等

目录 一、npm 安装二、完整引入三、按需引入四、样式修改1.按需加载的全局样式修改2. 局部样式修改1. 在 css 预处理器如 less scss 等直接使用::v-deep2. 只能用在原生 CSS 语法中:/deep/ 或者 >>> 五、 拓展&#xff1a;npm 安装less报错&#xff0c;提示证书过期六…

使用Go语言编写简单的HTTP服务器

在Go语言中&#xff0c;我们可以使用标准库中的"net/http"包来编写HTTP服务器。下面是一个简单的示例&#xff0c;展示了如何使用Go编写一个基本的HTTP服务器。 go复制代码 package main import ( "fmt" "net/http" ) …

红黑树浅浅学习

红黑树浅浅学习 红黑树概念红黑树平衡性调整 红黑树概念 二叉树&#xff1a;二叉树是每个节点最多有两个子树的树结构。二叉查找树&#xff1a;又称“二叉搜索树”&#xff0c;左孩子比父节点小&#xff0c;右孩子比父节点大&#xff0c;还有一个特性就是”中序遍历“可以让结…

机器学习实验报告——Bayes算法

目录 一、算法介绍 1.1算法背景 1.2算法假设 1.3 贝叶斯与朴素贝叶斯 1.4算法原理 二、算法推导 2.1朴素贝叶斯介绍 2.2朴素贝叶斯算法推导 2.2.1先验后验概率 2.2.2条件概率公式 2.3 独立性假设 2.4 朴素贝叶斯推导 三、算法实现 3.1数据集描述 3.2代码实现 四…

python04-变量命名规则

python需要使用标识符来给变量命名。 标识符&#xff0c;我来解释下&#xff0c;就是给程序中变量、类、方法命名的符号&#xff0c;简单理解就是起一个名字&#xff0c;这个名字必须是合法的名字&#xff0c; 对于Python来说&#xff0c;标识符必须是以字母、下划线(_)开头&…

性能优化-高通的Hexagon DSP和NPU

原文来自【 Qualcomm’s Hexagon DSP, and now, NPU 】 本文主要介绍Qualcomm Hexagon DSP和NPU&#xff0c;这些为处理简单大量运算而设计的硬件。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xf…

[足式机器人]Part2 Dr. CAN学习笔记- 最优控制Optimal Control Ch07-2 动态规划 Dynamic Programming

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记 - 最优控制Optimal Control Ch07-2 动态规划 Dynamic Programming 1. 基本概念2. 代码详解3. 简单一维案例 1. 基本概念 Richoard Bell man 最优化理论&#xff1a; An optimal policy has the …

Python + Selenium —— 常用控制方法!

Selenium 体系中用来操作浏览器的 API 就是 WebDriver&#xff0c;WebDriver 针对多种语言都实现了一套 API&#xff0c;支持多种编程语言。 Selenium 通常用来做自动化测试&#xff0c;或者编写网络爬虫。 通常我们说的 Selenium 自动化操作&#xff0c;指的就是 WebDriver …

LLM:RoPE - 开源代码中的实现 (下)

本文着重学习一下开源代码中关于RoPE的实现:ChatGLM-6B、ChatGLM2-6B、LLAMA 回顾一下RoPE位置编码: 1:对于 token 序列中的每个词嵌入向量,首先计算其对应的 query 和 key 向量 2:然后对每个 token 位置都计算对应的旋转位置编码 3:接着对每个 token 位置的 query 和 …

聊聊呼声较高的向量过滤搜索及其优化

向量过滤搜索是一种基于条件的向量搜索方法&#xff0c;常用于推荐系统和信息检索等领域&#xff0c;能够帮助用户快速找到在给定条件下与其查询相关的内容。 在 Milvus 社区中&#xff0c;这也是呼声比较高的功能。为满足广大用户的需求&#xff0c;Milvus 在 Knowhere 2.x 版…

通过Stable Diffusion生成虚假的遥感影像

简介 这两天玩了一下stable diffusion&#xff0c;是真的好玩&#xff01; 然后我在想遥感有没有相关的生成模型&#xff0c;找了一下&#xff0c;还真找到了&#xff08;https://github.com/xiaoyuan1996/Stable-Diffusion-for-Remote-Sensing-Image-Generation/tree/main&a…