跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

数据结构:外部排序原理与优化方法

介绍外部排序的基本原理,包括外存与内存间的数据处理逻辑、初始归并段的构造、多趟归并过程及时间开销分析。内容涵盖多路归并优化、败者树的应用以减少比较次数、置换 - 选择排序生成初始归并段的方法,以及基于哈夫曼树思想的最佳归并树构建策略。重点阐述了如何通过平衡读写操作和减少归并段数量来提升排序效率。

人间失格发布于 2026/3/27更新于 2026/9/1271 浏览
数据结构:外部排序原理与优化方法

图片描述

外部排序

1. 外存、内存之间的数据结构

特点:外存大,存储数据多;内存小,存储数据少。 规定:外存的数据只有读到内存之后才能进行修改,修改之后还要写回到外存(可以写回原来不同的位置)。

图片描述

2. 外部排序原理

简单来说,因为外存数据又多又杂,就要一点一点读入到内存中排序,然后再写回外存。 逻辑:外存–>读出数据–>内存–>在内存有序排列数据(比如一个块三个数据 632 排成 236)–>写回外存。

图片描述

2.1 构造初始归并段

因为内存腾出了两个存放数据块的位置(输入缓冲区)和写出数据的位置(输出缓冲区),2–>1,二合一就是二路归并。

从外存读入两个数据块放入内存的输入缓冲区内,然后就可以对这两个数据块进行归并排序了。

图片描述

得到两个有序数列。

图片描述

将这两个有序数列写回外存,这样就构成了一个有序的归并段。

图片描述

经过 16 次读和 16 次写,外存就变成了左边的 8 个归并段。

图片描述

2.2 第一趟归并

接下来就需要我们把归并段们继续归并排序:

  • 将两个归并段中小的数据块读入内存
  • 在内存中进行归并排序
  • 将排序好的数据写回外存

注意:写回的位置是另外一片,不是原来的存放未排序数据的位置。

图片描述

图片描述

出现一整个缓冲区空白的情况,就继续读入一个数据块,然后继续进行归并排序:

图片描述

图片描述

图片描述

图片描述

第一趟归并结束后,就成功得到了四个大的归并段:

图片描述

2.3 第二趟归并

和之前一样,挑出两个归并段中最小的一组,继续进行合并:

图片描述

图片描述

图片描述

第二趟合并后,就得到了两个更大的归并段:

图片描述

2.4 第三趟归并

最后,把这两个更大的归并段进行合并:

图片描述

最终就得到了有序的数据:

图片描述

3. 时间开销分析

  • 读写外存的时间:就是构造初始归并段的时间
  • 内部排序所需时间:就是排序花费的时间。
  • 内部归并所需时间:就是几次归并花费的时间。

图片描述

4. 优化

我们先对读写外存的这部分时间进行优化。

图片描述

4.1 多路归并

我们可以在内存多申请几个输入缓冲区,实现多路归并,一次读入两个数据段和一次读入四个数据段,当然是后者 I/O 次数更小,还可以减少归并的趟数。

假设:第一趟归并用 4 路归并

图片描述

图片描述

第一次归并后就得到两个归并段,只需要再一趟就可以完全有序:

图片描述

4.2 减少初始归并段数量

比如之前的我们的初始归并段是 8 个,现在减少为 4 个:

图片描述

4–>2–>1,得到初始归并段后再归并两次就可以完全有序了

图片描述

外存的总数据块数不变,初始归并段越长,初始归并段越少。

图片描述

5. 小结

图片描述

重点在平衡这两个字上:

图片描述

败者树

1. 多路平衡归并带来的问题

多路平衡归并:一个数要和很多个数都要比一次,才能找到最小的那个数字,就很浪费时间。

图片描述

2. 败者树的构造

就是两个人战斗,失败的留下,胜利的上去,继续和另一组胜利的人继续比,最终选出一个冠军。

图片描述

这个时候冠军跑路了:

图片描述

由派大星顶替它原来的位置

图片描述

那么难道我们还要重新比 7 次么?!

图片描述

答案是不需要,右侧的根本没被派大星影响,右侧胜利的依旧是孙悟空; 而派大星需要代替天津饭,先和阿乐比,赢了再和程龙比,赢了再和孙悟空比; 只需要比对三次就可以了

图片描述

3. 败者树的使用

同样的规则,我们就可以搬到归并段上使用。

画出败者树:

图片描述

每个归并段都排除自己最小的一个数字参赛:

  • 27>12,27 留,12 上;1<17,17 留,1 上;2<9,9 留,2 上;11>4,11 留,4 上;
  • 12>1,12 留,1 上;2<4,4 留,2 上
  • 1<2,2 留,1 上;
  • 上一次的冠军是 1,来自归并段 3,他就可以先走了
  • 继续用归并段 3 内的数字接力,6 出来沿着 1 的比赛路径进行比拼
  • 6<17,17 留,6 上,所以结点是 6 所在的归并段 3;
  • 12>6,12 留,6 上,所以结点是 6 所在的归并段 3;

最终回合:6>2,6 留,2 上,所以结点是 2 所在的归并段 5;

图片描述

这样就找出了最小的一个数

图片描述

注意:结点中记录的是来自的归并段,而不是真实数字

图片描述

所以再需要接着比赛选出最小的冠军,就只需要踩着前人的脚印,继续向上比拼。比如:

4. 败者树的实现思路

图片描述

图片描述

5. 小结

图片描述

图片描述

置换 - 选择排序

图片描述

1. 土办法构造初始归并段

纯一块一块构造。

图片描述

图片描述

2. 置换 - 选择排序

  • 工作区:只能放三个记录
  • MINIMAX:刚刚写出的数据的值
  • 规定:同一归并段,只能写出比 MINIMAX 大的数字

注意:这里的输出缓冲区省略了,但不代表没有

图片描述

选择工作区内最小的但比 4 大的数字写出:

图片描述

按照这个规律一直写出: 这里我们发现最小的一个数字是 10<13,而我们只能写出比 13 大的,所以就放着先不要动

图片描述

当工作区内的数字都比 MINIMAX 小,不可以写出的时候:

图片描述

我们就需要开一个新的归并段,经过写出最后是这样:

图片描述

最后就得到了三个不定长的归并段:

图片描述

注意:是有输出缓冲区存在的,只不过我们省略了而已

图片描述

3. 小结

图片描述

最佳归并树

1. 归并树的神秘性质

归并过程中的磁盘读写次数=归并树的 WPL*2 也就是最佳归并树是哈夫曼的形式

图片描述

2. 构造最佳归并树

2.1 2 路

图片描述

2.2 多路归并

图片描述

图片描述

如果减少一个归并段,那么单纯地按照哈夫曼树的逻辑处理得到的就不是最佳归并树了:

图片描述

我们需要添加一个结点 0,然后再按照正常的步骤继续进行:

图片描述

图片描述

3. 添加虚段的数量

情景:类似于上面缺少一个归并段的时候,我们需要添加几个结点 0? 结论:图片最后两行(代入例子更好理解)

图片描述

4. 小结

图片描述

图片描述

目录

  1. 外部排序
  2. 1. 外存、内存之间的数据结构
  3. 2. 外部排序原理
  4. 2.1 构造初始归并段
  5. 2.2 第一趟归并
  6. 2.3 第二趟归并
  7. 2.4 第三趟归并
  8. 3. 时间开销分析
  9. 4. 优化
  10. 4.1 多路归并
  11. 4.2 减少初始归并段数量
  12. 5. 小结
  13. 败者树
  14. 1. 多路平衡归并带来的问题
  15. 2. 败者树的构造
  16. 3. 败者树的使用
  17. 4. 败者树的实现思路
  18. 5. 小结
  19. 置换 - 选择排序
  20. 1. 土办法构造初始归并段
  21. 2. 置换 - 选择排序
  22. 3. 小结
  23. 最佳归并树
  24. 1. 归并树的神秘性质
  25. 2. 构造最佳归并树
  26. 2.1 2 路
  27. 2.2 多路归并
  28. 3. 添加虚段的数量
  29. 4. 小结

更多推荐文章

查看全部
  • Python 中 Pandas 库的基础使用指南
  • 手搓简易 Linux 进程池:基于管道的任务分发系统实现
  • 程序员如何实现薪资跃迁:从技术深耕到职业突破
  • ToDesk 集成 ToClaw:AI Agent 实现远程桌面自动化执行
  • 滑动窗口算法实战:最大连续 1 的个数 III 与将 x 减到 0 的最小操作数
  • 轻小说机翻机器人:架构设计与快速部署
  • 无人机视觉目标检测数据集 VisDrone 详解与数据预处理
  • 基于 WebGIS 的中国传统六大区域与身份证首位数字关联展示
  • HarmonyOS 6.0 OAID 服务正式支持 TV 设备
  • 苹果新款 Mac Studio 发布:M5 Ultra 性能提升 75%
  • 医疗领域自然语言处理(NLP)应用与实战指南
  • SLAM Toolbox 实战指南:机器人定位与建图核心技术
  • Spring AI Alibaba 集成 Redis 向量数据库实现 RAG 与记忆功能
  • 使用 LLaMA-Factory 进行大语言模型微调的全流程实战
  • Spring Boot 集成 Spring AI OpenAI Starter 教程
  • Python 3.12 日志核心:深入理解 LogRecord 机制
  • 使用 Python 绘制树木的几种方法
  • 二级 Python 考试真题及参考代码合集(简单应用题部分)
  • Linux 下 OpenClaw 快速安装、初始化与 Web UI 配置指南
  • 字节跳动豆包大模型发布,定价低于行业 99.3%

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online