Python 算法高级篇:归并排序的优化与外部排序
Python 算法高级篇:归并排序的优化与外部排序
- 引言
- 1. 归并排序的基本原理
- 2. 归并排序的优化
- 2.1 自底向上的归并排序
- 2.2 最后优化
- 3. 外部排序
- 4. 性能比较
- 5. 结论
引言
在计算机科学中,排序是一项基本的任务,而归并排序( Merge Sort )是一种著名的排序算法,它具有稳定性和良好的时间复杂度。本文将介绍归并排序的基本原理,然后深入探讨如何进行优化以及如何应用归并排序进行外部排序。
😃😄 ❤️ ❤️ ❤️
1. 归并排序的基本原理
归并排序采用分治的策略,将一个大问题分解为小问题,解决小问题,然后将它们合并以获得最终解决方案。其基本步骤如下:
- 1 . 分割( Divide ):将数组划分为两个子数组,通常是平均分割。
- 2 . 递归( Conquer ):递归地对子数组进行排序。
- 3 . 合并( Merge ):将排好序的子数组合并为一个有序的数组。
下面是一个简单的归并排序算法的 Python 实现:
def merge_sort(arr):if len(arr) > 1:mid = len(arr) // 2 # 找到数组的中间位置left_half = arr[:mid]right_half = arr[mid:]merge_sort(left_half) # 递归排序左半部分merge_sort(right_half) # 递归排序右半部分i = j = k = 0# 合并两个子数组while i < len(left_half) and j < len(right_half):if left_half[i] < right_half[j]:arr[k] = left_half[i]i += 1else:arr[k] = right_half[j]j += 1k += 1while i < len(left_half):arr[k] = left_half[i]i += 1k += 1while j < len(right_half):arr[k] = right_half[j]j += 1k += 1
归并排序的时间复杂度是 O ( n log n ),它是一种稳定的排序算法,但它需要额外的空间来存储临时数组。
2. 归并排序的优化
尽管归并排序的时间复杂度相对较低,但它在实际应用中可能会因为空间复杂度较高而受到限制。为了解决这个问题,可以进行一些优化。
2.1 自底向上的归并排序
传统的归并排序是自顶向下的,即从顶部开始递归划分子数组。在自底向上的归并排序中,我们从底部开始,首先将相邻的元素两两合并,然后是四四合并,八八合并,直到整个数组排序完成。这样可以减少递归所需的栈空间,降低空间复杂度。
以下是自底向上归并排序的 Python 实现:
def merge_sort_bottom_up(arr):n = len(arr)curr_size = 1while curr_size < n:for left in range(0, n - 1, 2 * curr_size):mid = min(left + curr_size - 1, n - 1)right = min(left + 2 * curr_size - 1, n - 1)if mid < right:merge(arr, left, mid, right)curr_size *= 2def merge(arr, left, mid, right):n1 = mid - left + 1n2 = right - midL = [0] * n1R = [0] * n2for i in range(n1):L[i] = arr[left + i]for i in range(n2):R[i] = arr[mid + i + 1]i = j = 0k = leftwhile i < n1 and j < n2:if L[i] <= R[j]:arr[k] = L[i]i += 1else:arr[k] = R[j]j += 1k += 1while i < n1:arr[k] = L[i]i += 1k += 1while j < n2:arr[k] = R[j]j += 1k += 1
2.2 最后优化
归并排序的一个缺点是它需要额外的空间来存储临时数组。为了避免这种情况,可以使用一个额外的数组来存储一半的数据,然后交替地将数据复制到原始数组中。这可以降低空间复杂度,但增加了一些额外的复制操作。
以下是这种优化方法的 Python 实现:
def merge_sort_optimized(arr):n = len(arr)temp_arr = [0] * ncurr_size = 1while curr_size < n:left = 0while left < n - 1:mid = min(left + curr_size - 1, n - 1)right = min(left + 2 * curr_size - 1, n - 1)if mid < right:merge_optimized(arr, left, mid, right, temp_arr)left += 2 * curr_sizecurr_size *= 2def merge_optimized(arr, left, mid, right, temp_arr):i = leftj = mid + 1for k in range(left, right + 1):temp_arr[k] = arr[k]k = leftwhile i <= mid and j <= right:if temp_arr[i] <= temp_arr[j]:arr[k] = temp_arr[i]i += 1else:arr[k] = temp_arr[j]j += 1k += 1while i <= mid:arr[k] = temp_arr[i]k += 1i += 1
这种优化方法减少了内存的使用,但增加了一些额外的复制操作。
3. 外部排序
归并排序还可以应用于外部排序,这是一种处理大规模数据集的排序方法。外部排序的主要思想是将大数据集分成多个小数据块,每个小数据块都可以在内存中进行排序。排序后,将这些小数据块合并成一个有序的大数据集。
下面是一个简单的外部排序示例,假设我们有一个非常大的文件,无法一次性加载到内存中进行排序。我们可以将文件划分为多个小文件块,分别进行排序,然后合并它们。
def external_sort(input_file, output_file, chunk_size):# 划分文件为多个块divide_file(input_file, chunk_size)# 对每个块进行内部排序sort_chunks()# 合并排序后的块merge_sorted_chunks(output_file)def divide_file(input_file, chunk_size):# 从输入文件中读取数据并划分为块passdef sort_chunks():# 对每个块进行内部排序passdef merge_sorted_chunks(output_file):# 合并排序后的块pass
这个示例演示了如何将大文件划分为多个小文件块,每个块都可以在内存中排序。然后,排序后的块将被合并为一个有序的输出文件。
4. 性能比较
为了演示归并排序的不同优化版本之间的性能差异,我们可以使用一些基准测试来比较它们的运行时间。下面是一个简单的性能比较示例:
import random
import timeitarr = [random.randint(1, 1000) for _ in range(1000)]# 未优化的归并排序
def merge_sort_original(arr):if len(arr) > 1:mid = len(arr) // 2left_half = arr[:mid]right_half = arr[mid:]merge_sort_original(left_half)merge_sort_original(right_half)i = j = k = 0while i < len(left_half) and j < len(right_half):if left_half[i] < right_half[j]:arr[k] = left_half[i]i += 1else:arr[k] = right_half[j]j += 1k += 1while i < len(left_half):arr[k] = left_half[i]i += 1k += 1while j < len(right_half):arr[k] = right_half[j]j += 1k += 1# 测试未优化的归并排序的性能
original_time = timeit.timeit(lambda: merge_sort_original(arr.copy()), number=1000)# 优化的归并排序
def merge_sort_optimized(arr):# 同上,省略优化后的代码# 测试优化的归并排序的性能
optimized_time = timeit.timeit(lambda: merge_sort_optimized(arr.copy()), number=1000)print("未优化的归并排序耗时:", original_time)
print("优化的归并排序耗时:", optimized_time)
在上述示例中,我们对未优化的归并排序和优化后的归并排序进行了性能测试。通过这种方式,你可以比较它们的性能并选择最适合你应用的版本。
5. 结论
归并排序是一种经典的排序算法,它使用分治策略和合并操作,具有稳定的性质和较低的时间复杂度。通过进行优化,例如自底向上的归并排序和减少内存使用的外部排序,我们可以提高归并排序的性能和适用性。根据应用的需求和资源限制,选择合适的排序算法版本,以获得最佳性能。这些优化方法可以在处理大数据集和内存受限的情况下发挥重要作用。
[ 专栏推荐 ]
😃 《Python 算法初阶:入门篇》😄
❤️【简介】:本课程是针对 Python 初学者设计的算法基础入门课程,涵盖算法概念、时间复杂度、空间复杂度等基础知识。通过实例演示线性搜索、二分搜索等算法,并介绍哈希表、深度优先搜索、广度优先搜索等搜索算法。此课程将为学员提供扎实的 Python 编程基础与算法入门,为解决实际问题打下坚实基础。
相关文章:

Python 算法高级篇:归并排序的优化与外部排序
Python 算法高级篇:归并排序的优化与外部排序 引言 1. 归并排序的基本原理2. 归并排序的优化2.1 自底向上的归并排序2.2 最后优化 3. 外部排序4. 性能比较5. 结论 引言 在计算机科学中,排序是一项基本的任务,而归并排序( Merge S…...
LeetCode--1991.找到数组的中间位置
1 题目描述 给你一个下标从 0 开始的整数数组 nums , 请你找到 最左边 的中间位置 middleIndex (也就是所有可能中间位置下标最小的一个) 中间位置 middleIndex 是满足 nums[0] nums[1] ... nums[middleIndex-1] nums[middleIndex1] nums[middleI…...
物联网数据采集网关连接设备与云平台的关键桥梁
随着工业4.0和智能制造的快速发展,物联网数据采集网关在工业物联网中的应用越来越广泛。物联网数据采集网关作为连接设备与云端之间的关键桥梁,能够实现高效、可靠、安全的数据传输和转换,为智能制造和工业4.0提供了强大的支持。 一、物联网…...

专家级数据恢复:UFS Explorer Professional Recovery Crack
UFS Explorer Professional Recovery - 一款功能强大且方便的数据恢复程序,支持检测大量文件系统、操作系统和各种类型的驱动器:从简单的闪存驱动器到复杂的复合存储(各种级别的 RAID 阵列)。 该程序由执业专家开发,并…...

2023/10/23 mysql学习
数据库修改 show databases; 展示所有数据库 create database 数据库名; 创建数据库 create database if not exists 数据库名; 如果未创建过当前数据库名则创建 drop database 数据库名; drop database if exists 数据库名;用法和创建类似 删除数据库 use 数据库名; 跳…...

软考系统架构师知识点集锦六:项目管理
一、考情分析 二、考点精讲 2.1进度管理(时间管理) 进度管理:为了确保项目按期完成所需要的管理过程。 2.1.1过程 [WBS分解的基本要求] WBS的工作包是可控和可管理的,不能过于复杂。任务分解也不能过细,一般原则WBS的树形结构不超过6层。每个工作包要…...

MacOS系统Chrome开发者模式下载在线视频
操作流程 # step1. 进入开发者模式 command option i # step2. 在搜索栏中搜索 getHttpVideoInfo.do?关键词 # step3. 在Preview的Json界面中找到video,然后选择不同resolution & duration的视频片段; # step4. 选择合适的video::chapters, 选择…...
uniapp v3+ts 使用 u-upload上传图片以及视频
上传图片方法 <u-upload :fileList"fileList1" afterRead"afterRead" delete"deletePic" name"file" multiple :maxCount"6"></u-upload> // maxCount 最大上传数const fileList1 ref([]);const file ref([…...
为什么虚拟dom会提高性能?
虚拟 DOM(Virtual DOM)是一种在前端开发中常用的技术,它可以提高性能并改善用户体验。虚拟 DOM 的原理和用处如下: 原理: 当页面状态发生变化时,虚拟 DOM 会以 JavaScript 对象的形式进行更新,而…...

2015年亚太杯APMCM数学建模大赛A题海上丝绸之路发展战略的影响求解全过程文档及程序
2015年亚太杯APMCM数学建模大赛 A题 海上丝绸之路发展战略的影响 原题再现 一带一路不是实体或机制,而是合作与发展的理念和主张。凭借现有有效的区域合作平台,依托中国与有关国家现有的双边和多边机制,利用古丝绸之路的历史象征࿰…...

js中HTMLCollection如何循环
//不带索引 let divCon document.getElementsByClassName("el-form-item__error"); if (divCon.length > 0) {for (var item of divCon) {console.log("打印:", item.innerText);} }//带有索引 let divCon document.getElementsByClassNam…...

Kafka - 3.x 副本不完全指北
文章目录 kafka 副本的基本信息Leader选举过程Kafka Controllerkafka 分区副本Leader的选举流程实际演示① 查看first的详细信息,注意观察副本分布情况② 停掉hadoop103上的kafka进程③ 再次查看first的相信信息,观察副本分布④ 处理分区leader分布不均匀…...

二分归并法将两个数组合并
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> main() {int a[5] {1,3,4,5,6};int b[4] {2,7,8,9};int c[9];int m0, n0,k0;while (m < 5 && n < 4){if (a[m] < b[n]){c[k] a[m];//谁小谁先进数组m; k;}else{c[k] b[n];k; n;}}while (m <…...
ROS自学笔记十六:URDF优化_xacro文件
xacro 是一种 XML 扩展语言,用于创建和维护 URDF(Unified Robot Description Format)文件。它允许你使用参数化、宏和条件语句等功能来更灵活、更可维护地定义机器人模型。下面是关于 xacro 的详细解释: 1. 参数化(Par…...
XMLHttpRequest拦截请求和响应
环境: angular 实现: 拦截请求 向请求信息增加字段 拦截响应 过滤返回值 响应拦截: 根据angular使用的XMLHttpRequest 将对原本的请求转移到另一个将监听返回事件挂载到另一个世纪发送请求的xml上 使用get set 将客户端获取的res…...

前端 读取/导入 Excel文档
情况: 需要通过Excel表,将数据导入到数据库,但是后台人员出差了,我又只会PHP,没用过node,所以只能前端导入Excel文件,然后循环调用后台的单条添加接口了。 库: Excel.js(…...
聊聊springboot的TomcatMetricsBinder
序 本文主要研究一下springboot的TomcatMetricsBinder TomcatMetricsAutoConfiguration org/springframework/boot/actuate/autoconfigure/metrics/web/tomcat/TomcatMetricsAutoConfiguration.java Configuration(proxyBeanMethods false) ConditionalOnWebApplication C…...

《动手学深度学习 Pytorch版》 10.6 自注意力和位置编码
在注意力机制中,每个查询都会关注所有的键-值对并生成一个注意力输出。由于查询、键和值来自同一组输入,因此被称为 自注意力(self-attention),也被称为内部注意力(intra-attention)…...
2023年第四届MathorCup高校数学建模挑战赛——大数据竞赛B题 实现代码
根据之前发布的思路 第一步 进行数据合并 import pandas as pd# 读取所有附件的数据 data1 pd.read_excel(附件一.xlsx) data2 pd.read_excel(附件二.xlsx) data3 pd.read_excel(附件三.xlsx) data4 pd.read_excel(附件四.xlsx)# 根据商品编码将附件一和附件二连接 combi…...
larvel 中的api.php_Laravel 开发 API
Laravel10中提示了Target *classController does not exist,为什么呢? 原因是:laravel8开始写法变了。换成了新的写法了 解决方法一: 在路由数组加入App\Http\Controllers\即可。 <?phpuse Illuminate\Support\Facades\Route;…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...