第8章 文件管理和外排序 任课教员:张 铭 http://db.pku.edu.cn/mzhang/DS/ 任课教员:张 铭 http://db.pku.edu.cn/mzhang/DS/ mzhang@db.pku.edu.cn 北京大学信息科学与技术学院 网络与信息系统研究所 版权所有,转载或翻印必究.

Slides:



Advertisements
Similar presentations
7.1 内置对象概述及分类 JSP 视频教学课程. JSP2.2 目录 1. 内置对象简介 1. 内置对象简介 2. 内置对象分类 2. 内置对象分类 3. 内置对象按功能区分 3. 内置对象按功能区分 4. 内置对象作用范围 4. 内置对象作用范围.
Advertisements

1 物料管理 EXST 1 Algorithms and Data Structures:EXSORT 1 、外存信息的存取 1 、外部排序: 内部排序:信息一次可全部调入内存,信息在内存中的处理时间是主要的时间耗费。 外部排序:信息量巨大,无法一次调入内存。只能驻留在带、盘。特点为内存运行时 间短,内、外存进行交换需要时间长。减少.
第三章 数据类型和数据操作 对海量数据进行有效的处理、存储和管理 3.1 数据类型 数据源 数据量 数据结构
小学生游戏.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
第九章 字符串.
Hadoop I/O By ShiChaojie.
强连通分量 无向图 1、任意两顶点连通称该图为连通图 2、否则将其中的极大连通子图称为连通分量 A D C B E 有向图
存储系统.
走进编程 程序的顺序结构(二).
辅导课程六.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第十章 IDL访问数据库 10.1 数据库与数据库访问 1、数据库 数据库中数据的组织由低到高分为四级:字段、记录、表、数据库四种。
以ISI平台为例,为您演示一下如何在Endnote文献中查看该文献的References
Online job scheduling in Distributed Machine Learning Clusters
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
如何生成设备节点 广州创龙电子科技有限公司
CPU结构和功能.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
使用矩阵表示 最小生成树算法.
Java语言程序设计 清华大学出版社 第8章 输入输出流(1).
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
无向树和根树.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
微机系统的组成.
顺序表的删除.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
线 性 代 数 厦门大学线性代数教学组 2019年4月24日6时8分 / 45.
VB与Access数据库的连接.
姚金宇 MIT SCHEME 使用说明 姚金宇
分裂对象模型 C++ otcl.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
Lightweight Data-flow Analysis for Execution-driven Constraint Solving
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第4章 Excel电子表格制作软件 4.4 函数(一).
iSIGHT 基本培训 使用 Excel的栅栏问题
§6.7 子空间的直和 一、直和的定义 二、直和的判定 三、多个子空间的直和.
3.16 枚举算法及其程序实现 ——数组的作用.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
本节内容 文件系统 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第4课时 绝对值.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
Visual Basic程序设计 第13章 访问数据库
GIS基本功能 数据存储 与管理 数据采集 数据处理 与编辑 空间查询 空间查询 GIS能做什么? 与分析 叠加分析 缓冲区分析 网络分析
正弦、余弦函数的性质 华容一中 伍立华 2017年2月24日.
Python 环境搭建 基于Anaconda和VSCode.
本节内容 结构体.
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
第六章 Excel的应用 五、EXCEL的数据库功能 1、Excel的数据库及其结构 2、Excel下的数据排序 (1)Excel的字段名行
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第8章 创建与使用图块 将一个或多个单一的实体对象整合为一个对象,这个对象就是图块。图块中的各实体可以具有各自的图层、线性、颜色等特征。在应用时,图块作为一个独立的、完整的对象进行操作,可以根据需要按一定比例和角度将图块插入到需要的位置。 2019/6/30.
第四章 UNIX文件系统.
第十七讲 密码执行(1).
第十二讲 密码执行(上).
插入排序的正确性证明 以及各种改进方法.
FVX1100介绍 法视特(上海)图像科技有限公司 施 俊.
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
§4.5 最大公因式的矩阵求法( Ⅱ ).
RefWorks使用指南 归档、管理个人参考文献.
<编程达人入门课程> 本节内容 有符号数与无符号数 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第二次课后作业答案 函数式编程和逻辑式编程
最小生成树 最优二叉树.
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
Presentation transcript:

第8章 文件管理和外排序 任课教员:张 铭 http://db.pku.edu.cn/mzhang/DS/ 任课教员:张 铭 http://db.pku.edu.cn/mzhang/DS/ mzhang@db.pku.edu.cn 北京大学信息科学与技术学院 网络与信息系统研究所 版权所有,转载或翻印必究

为什么需要文件管理和外排序? 文件结构( file structure ) 文件的各种运算 数据量太大不可能同时把它们放到内存中 需要把全部数据放到磁盘中 文件的各种运算 外排序是针对磁盘文件所进行的排序操作 提高文件存储效率和运算效率 北京大学信息学院 Page 2

本章的安排顺序 8.1 介绍主存和外存的根本差异 8.2 在外存中文件的组织方式 8.3 管理缓冲池的基本方法 8.4 外排序的基本算法 北京大学信息学院 Page 3

主存储器和外存储器 主存储器( primary memory或者main memory ,简称“内存”,或者“主存”) 随机访问存储器( Random Access Memory, 即RAM ) 高速缓存( cache ) 视频存储器( video memory ) 。 外存储器(peripheral storage或者secondary storage,简称“外存”) 硬盘 软盘 磁带 北京大学信息学院 Page 4

主存储器和外存储器 之价格比较 介质 2001年底价格 2002年底价格 2003年早期价格 内存 1 1.5 硬盘 0.017 0.013 0.011 软盘 12 7 2.5 磁带 0.008 0.0075 北京大学信息学院 Page 5

外存的优缺点 尽量减少访外次数! 优点:永久存储能力、便携性 缺点:访问时间长 访问磁盘中的数据比访问内存慢五六个数量级。 所以讨论在外存的数据结构及其上的操作时,必须遵循下面这个重要原则: 尽量减少访外次数! 北京大学信息学院 Page 6

磁盘的物理结构 北京大学信息学院 Page 7

磁盘盘片的组织 北京大学信息学院 Page 8

磁盘存取步骤 选定某个盘片组 选定某个柱面 确定磁道 确定所要读写的数据在磁盘上的准确位置 真正进行读写 这需要把磁头移动到该柱面 ,这个移动过程称为寻道( seek ) 确定磁道 确定所要读写的数据在磁盘上的准确位置 这段时间一般称为旋转延迟( rotational delay 或者rotational latency ) 真正进行读写 北京大学信息学院 Page 9

磁盘磁道的组织(交错法) (a)没有扇区交错;(b)以3为交错因子 北京大学信息学院 Page 10

磁盘访问时间估算 磁盘访问时间主要由寻道时间、旋转延迟时间和数据传输时间组成。 寻道时间(Seek time):是移动磁盘臂,定位到正确磁道所需的时间。 旋转延迟时间:是等待被存取的扇区出现在读写头下所需的时间。 北京大学信息学院 Page 11

总存取时间(1) (1)数据连续存放,而且给出了平均寻道时间。 总存取时间 = [平均寻道时间] + [第一道读取时间] 总存取时间 = [平均寻道时间] + [第一道读取时间] + (总磁道数–1)[(第二次寻道时间)+(读取整道的时间)] = [平均寻道时间] + [(0.5圈延迟+交错因子)  每圈所花时间] + (总磁道数–1)  [磁道转换时间+(0.5圈延迟+交错因子)每圈所花时间] 北京大学信息学院 Page 12

总存取时间(2) (2)数据随机存放 。 总存取时间 = 簇数  {[平均寻道时间]+[旋转延迟]+[读一簇时间]} 总存取时间 = 簇数  {[平均寻道时间]+[旋转延迟]+[读一簇时间]} = 簇数  {[平均寻道时间] + [0.5圈延迟每圈所花时间] + [交错因子(每簇扇区数/每道扇区数)每圈时间]} 北京大学信息学院 Page 13

例8.1 假定一个磁盘总容为16.8GB,分布在10个盘片上。每个盘片上有13085个磁道,每个磁道中包含256个扇区,每个扇区512个字节,每个簇8个扇区。扇区的交错因子是3。磁盘旋转速率是5400 rpm,磁道转换时间是2.2 ms,随机访问的平均寻道时间是9.5 ms。 北京大学信息学院 Page 14

如果读取一个1MB的文件,该文件有2048个记录,每个记录有512字节(1个扇区)。对于以下两种情况,估算进行文件处理的总时间。 (1)假定所有记录在8个连续磁道上; (2)假定文件簇随机地散布在磁盘上。 北京大学信息学院 Page 15

解:我们先总结出一些共有的特性 每个簇为4KB 每个磁道有32簇 每个盘片有1.68GB 每转一圈的时间为11.1ms 8个扇区 = 512 byets × 8 = 4KB 每个磁道有32簇 256个扇区 = 256 扇区 8(扇区/簇) = 32个簇 每个盘片有1.68GB 16.8GB  10 = 1.68GB 每转一圈的时间为11.1ms (60×1000)ms/5400圈 = 11.1(ms/圈)= 11.1(ms/道) 一个磁道是一个整圈,因此,下面计算公式中,所用的单位“圈”等同于“道” 北京大学信息学院 Page 16

+ [(0.5圈延迟+交错因子)  每圈所花时间] + (总磁道数–1)  [磁道转换时间+(0.5圈延迟+交错因子)每圈所花时间] 数据连续存放,而且给出了平均寻道时间。 总存取时间 = [平均寻道时间] + [(0.5圈延迟+交错因子)  每圈所花时间] + (总磁道数–1)  [磁道转换时间+(0.5圈延迟+交错因子)每圈所花时间] = [9.5ms(平均寻道时间)] + [(0.5(半圈旋转延迟) + 3(交错因子))11.1ms/圈 +(8-1)个其他磁道  [2.2ms磁道转换时间+(0.5圈延迟+3交错因子)11.1ms/圈] = 9.5ms + 38.9ms + 7  41.1ms = 336.1ms 北京大学信息学院 Page 17

+ [交错因子(每簇扇区数/每道扇区数)每圈时间]} = 256 { [9.5ms(平均寻道时间)] 数据随机存放 总簇数:8个磁道  32(簇/磁道) = 256簇 总存取时间 = 簇数  {[平均寻道时间] + [0.5圈延迟每圈所花时间] + [交错因子(每簇扇区数/每道扇区数)每圈时间]} = 256 { [9.5ms(平均寻道时间)] + [0.5(半圈旋转延迟)11.1ms/圈] + [3(交错因子)8(扇区/簇/)256(扇区/道) 11.1ms/圈]}  256  {9.5 + 5.55 + 1.04}ms  4119.04ms 北京大学信息学院 Page 18

读一簇的时间 定位后,实际读一簇数据的时间 读一个字节的时间 “一次访外”操作 [9.5ms(平均寻道时间)]+[0.5(半圈旋转延迟)11.1ms/圈+[1扇区256(扇区/道) 11.1ms/圈] = 9.5 + 5.55 + 1.04= 16.09ms 定位后,实际读一簇数据的时间 [3(交错因子)8(扇区/簇/)256(扇区/道) 11.1ms/圈]  1.04ms 读一个字节的时间 [9.5ms(平均寻道时间)]+[0.5(半圈旋转延迟)11.1ms/圈] = 15.05ms “一次访外”操作 磁盘一次I/O操作访问一个扇区,通常称为访问“一页”(page),或者“一块”(block) 北京大学信息学院 Page 19

磁带 主要优点 :使用方便、价格便宜、容量大、所存储的信息比磁盘和光盘更持久 缺点:速度较慢,只能进行顺序存取 北京大学信息学院 Page 20

磁带卷在一个卷盘上,运行时磁带经过读写磁头,把磁带上的信息读入计算机,或把计算机中的信息写在磁带上。 磁带运行示意图 磁带卷在一个卷盘上,运行时磁带经过读写磁头,把磁带上的信息读入计算机,或把计算机中的信息写在磁带上。 北京大学信息学院 Page 21

磁带发展史 手工阶段 自动化磁带库系统 虚拟磁带技术 北京大学信息学院 Page 22

外存文件的组织 职工号 姓名 性别 职务 工资 156 张东 男 程序员 未婚 7800 860 李珍 女 分析员 已婚 8900 510 婚姻状况 工资 156 张东 男 程序员 未婚 7800 860 李珍 女 分析员 已婚 8900 510 赵莉 6900 950 陈萍 6200 620 周力 10300 文件是一些记录的汇集,其中每个记录由一个或多个数据项组成。 数据项有时也称为字段,或者称为属性。例如,一个职工文件里的记录可以包含下列数据项:职工号,姓名,性别,职务,婚姻状况,工资等。 北京大学信息学院 Page 23

文件组织 逻辑文件 对高级程序语言的编程人员而言,存储在磁盘中可以随机访问的文件被当作一段连续的字节,而且可以把这些字节结合起来构成记录,这种文件被称为逻辑文件( logical file )。 物理文件 实际存储在磁盘中的物理文件( physical file )通常不是一段连续的字节,而是成块地分布在整个磁盘中。 文件管理器 是操作系统的一部分,当应用程序请求从逻辑文件中读解数据时,它把这些逻辑位置映射为磁盘中具体的物理位置。 北京大学信息学院 Page 24

文件的逻辑结构 文件是记录的汇集。 因而,文件可看成是一种线性结构。 当一个文件的各个记录按照某种次序排列起来时,各纪录间就自然地形成了一种线性关系。 因而,文件可看成是一种线性结构。 北京大学信息学院 Page 25

文件的存储结构 顺序结构——顺序文件 计算寻址结构——散列文件 带索引的结构——带索引文件 北京大学信息学院 Page 26

文件上的操作 检索:在文件中寻找满足一定条件的记录 修改:是指对记录中某些数据值进行修改。若对关键码值进行修改,这相当于删除加插入。 插入:向文件中增加一个新记录。 删除:从文件中删去一个记录 。 排序 :对指定好的数据项,按其值的大小把文件中的记录排成序列,较常用的是按关键码值的排序。 北京大学信息学院 Page 27

C++的流文件 C++程序员对随机访问文件的逻辑视图是一个单一的字节流,即字节数组。 程序员需要管理标志文件当前位置的文件指针。 常见的三个基本文件操作,都是围绕文件指针进行的: 把文件指针设置到指定位置(移动文件指针) 从文件的当前位置读取字节 向文件中的当前位置写入字节 北京大学信息学院 Page 28

C++操作二进制文件的常用方式——fstream类 fstream类的主要成员函数包括open,close,read,write,seekg,seekp。 北京大学信息学院 Page 29

fstream类的主要函数成员 #include<fstream.h>//fstream=ifstream+ofstream // 打开文件进行处理。 // 模式示例: ios::in | ios::binary void fstream::open(char* name, openmode mode); // 处理结束后关闭文件。 void fstream::close(); 北京大学信息学院 Page 30

ftream类的主要函数成员(续1) // 从文件当前位置读入一些字节。 // 随着字节的读入,文件当前位置向前移动。 fstream::read(char* ptr, int numbytes); // 向文件当前位置写入一些字节 // (覆盖已经在这些位置的字节)。 // 随着字节的写入,文件当前位置向前移动。 fstream::write(char* ptr, int numbtyes); 北京大学信息学院 Page 31

ftream类的主要函数成员(续2) // seekg和seekp:在文件中移动当前位置, // 这样就可以在文件中的任何一个位置 // 读出或写入字节。 // 实际上有两个当前位置, //一个用于读出,另一个用于写入。 // 函数seekg用于改变读出位置, // 函数seekp用于改变写入位置 fstream::seekg(int pos); // 处理输入 fstream::seekg(int pos, ios::curr); fstream::seekp(int pos); // 处理输出 fstream::seekp(int pos, ios::end); 北京大学信息学院 Page 32

缓冲 目的:减少磁盘访问次数的 方法:缓冲( buffering )或缓存( caching ) 在内存中保留尽可能多的块 可以增加待访问的块已经在内存中的机会,因此就不需要访问磁盘 北京大学信息学院 Page 33

缓冲区和缓冲池 存储在一个缓冲区中的信息经常称为一页( page ),往往是一次I/O的量 缓冲区合起来称为缓冲池( buffer pool ) 北京大学信息学院 Page 34

替换缓冲区块的策略 “先进先出”(FIFO) “最不频繁使用”(LFU) “最近最少使用”(LRU) 北京大学信息学院 Page 35

虚拟存储 ( virtual memory ) 虚拟存储使得程序员能够使用比实际内存更大的内存空间。 磁盘中存储虚拟存储器的全部的内容,根据存储器的访问需要把块读入内存缓冲池。 北京大学信息学院 Page 36

虚拟存储 系统运行到某一时刻,虚拟地址空间中有5个页被读入到物理内存中,现在如果需要对地址为24k-28k的页进行访问,就必须替换掉当前物理内存中的一个页框。 北京大学信息学院 Page 37

外排序 外排序( external sort ) 外部排序算法的主要目标是尽量减少读写磁盘的次数 外存设备上(文件)的排序技术 由于文件很大,无法把整个文件的所有记录同时调入内存中进行排序,即无法进行内排序 外部排序算法的主要目标是尽量减少读写磁盘的次数 北京大学信息学院 Page 38

关键码索引排序 索引文件( index file )中 对索引文件进行排序,所需要的I/O操作更少 关键码与指针一起存储 指针标识相应记录在原数据文件中的位置 对索引文件进行排序,所需要的I/O操作更少 索引文件比整个数据文件小很多。 在一个索引文件中,只针对关键码排序( key sort )。 北京大学信息学院 Page 39

磁盘排序过程 顺串:用某种有效的内排序方法对文件的各段进行初始排序,这些经过排序的段通常称为顺串( run ) ,它们生成之后立即被写回到外存上。 磁盘排序过程: 文件分成若干尽可能长的初始顺串; 逐步归并顺串归,最后形成一个已排序的文件。 北京大学信息学院 Page 40

置换选择排序 采用置换选择算法,在扫描一遍的前提下,使得所生成的各个顺串有更大的长度。这样减少了初始顺串的个数,有利于在合并时减少对数据的扫描遍数。 北京大学信息学院 Page 41

置换选择算法 假设外排序算法可以使用一个输入缓冲区、一个输出缓冲区、一个能存放M个记录的RAM内存块(可以看成大小为M的连续数组)。排序操作可以利用缓冲区,但只能在RAM中进行。 平均情况下,这种算法可以创建长度为2M个记录的顺串。 北京大学信息学院 Page 42

置换选择方法图示 处理过程为:从输入文件读取记录(一整块磁盘中所有记录),进入输入缓冲区;然后在RAM中放入待排序记录;记录被处理后,写回到输出缓冲区;输出缓冲区写满的时候,把整个缓冲区写回到一个磁盘块。当输入缓冲区为空时,从磁盘输入文件读取下一块记录。 北京大学信息学院 Page 43

置换选择算法 1. 初始化堆: (a) 从磁盘读M个记录放到数组RAM中。 (b) 设置堆末尾标准LAST = M - 1。 1.       初始化堆: (a)    从磁盘读M个记录放到数组RAM中。 (b)    设置堆末尾标准LAST = M - 1。 (c)    建立一个最小值堆。 北京大学信息学院 Page 44

置换选择算法(续) 2. 重复以下步骤,直到堆为空(即LAST < 0): (a) 把具有最小关键码值的记录(根结点)送到输出缓冲区。 (b) 设R是输入缓冲区中的下一条记录。如果R的关键码值大于刚刚输出的关键码值…… i. 那么把R放到根结点。 ii. 否则使用数组中LAST位置的记录代替根结点,然后把R放到LAST位置。设置LAST = LAST - 1。 (c)重新排列堆,筛出根结点。 北京大学信息学院 Page 45

置换选择示例(1) 北京大学信息学院 Page 46

置换选择示例(2) 北京大学信息学院 Page 47

置换选择示例(3) 北京大学信息学院 Page 48

置换选择算法的实现 ////置换选择算法 //模板参数Elem代表数组中每一个元素的类型 //A是从外存读入n个元素后所存放的数组,n是数组元素的个数 //in和out分别是输入和输出文件名 template <class Elem> void replacementSelection(Elem * A, int n, const char * in, const char * out){ 北京大学信息学院 Page 49

置换选择算法的实现(续1) Elem mval; //存放最小值堆的最小值 Elem r; //存放从输入缓冲区中读入的元素 //输入、输出文件句柄 FILE * inputFile; FILE * outputFile;  //输入、输出buffer Buffer<Elem> input; Buffer<Elem> output; //初始化输入输出文件 initFiles(inputFile, outputFile, in, out); 北京大学信息学院 Page 50

置换选择算法的实现(续2) /********** 算法主体部分 ***********/ //初始化堆的数据, // 从磁盘文件读入n个数据置入数组A initMinHeapArry(inputFile, n, A); //建立最小值堆 MinHeap<Elem> H(A, n, n); 北京大学信息学院 Page 51

置换选择算法的实现(续3) //初始化input buffer,读入一部分数据 initInputBuffer(input, inputFile); for(int last = (n-1); last >= 0;){ //堆不为空,就做这个循环 mval = H.heapArray[0]; //堆的最小值 //把mval送到输出缓冲区, //同时处理因缓冲区空或满造成的各种情形 sendToOutputBuffer(input, output, inputFile, outputFile, mval); 北京大学信息学院 Page 52

置换选择算法的实现(续4) input.read(r); //从输入缓冲区读入一个记录 if(!less(r, mval)){ //若r的关键码值大于等于刚才输出缓冲区记录的关键码值,//把r放到根结点 H.heapArray[0] = r; } else { //否则用last位置的记录代替根结点,把r放到last位置 H.heapArray[0] = H.heapArray[last]; H.heapArray[last] = r; H.setSize(last); last--; 北京大学信息学院 Page 53

置换选择算法的实现(续5) H.SiftDown(0); //把根结点记录下降到合适的位置 } //for //算法结束工作: //处理输出缓冲区,输入/输出文件 endUp(output, inputFile, outputFile); } 北京大学信息学院 Page 54

置换选择算法的效果 如果堆的大小是M 一个顺串的最小长度就是M个记录 至少原来在堆中的那些记录将成为顺串的一部分 最好的情况下,例如输入已经被排序,有可能一次就把整个文件生成为一个顺串。 北京大学信息学院 Page 55

扫雪机模型 扫雪机模型显示扫雪机在环绕一圈过程中的行为。根据“扫雪机”模型的分析,可以预计平均情况下顺串总长度是数组长度的两倍。 北京大学信息学院 Page 56

二路外排序 归并原理:把第一阶段所生成的顺串加以合并(例如通过若干次二路合并),直至变为一个顺串为止,即形成一个已排序的文件。 北京大学信息学院 Page 57

二路归并外排序 北京大学信息学院 Page 58

多路归并 三路归并 北京大学信息学院 Page 59

选择树 在K路归并中,最直接的方法就是作K-1次比较来找出所要的记录,但这样做花的代价较大,我们采用选择树的方法来实现K路归并。 选择树是完全二叉树,有两种类型:赢者树和败方树。 北京大学信息学院 Page 60

赢者树 叶子节点用数组L表示 分支节点用数组B表示 因此,根结点是树中的最终赢者的索引,即为下一个要输出的记录结点。 代表各顺串在合并过程中的当前记录(图中标出了它们各自的关键码值); 分支节点用数组B表示 每个分支节点代表其两个儿子结点中的赢者(关键码值较小的)所对应数组L的索引。 因此,根结点是树中的最终赢者的索引,即为下一个要输出的记录结点。 北京大学信息学院 Page 61

赢者树示例(1) 根结点所指向的L[4]记录具有最小的关键码值6,它所指的记录是顺串4的当前记录,该记录即为下一个要输出的记录。 北京大学信息学院 Page 62

赢者树示例(2) 重构后的赢者树,改动的节点用较粗的框显示出来。为了重构这颗树,只须沿着从结点L[4]到根结点的路径重新进行比赛。 北京大学信息学院 Page 63

赢者树ADT template<class T> class WinerTree{ public: Create(); //创建一个空的赢者树 Iitialize(T a[], int n); //返回比赛的赢者 Replay(i); //选手i变化时,重建赢者树 }; 北京大学信息学院 Page 64

赢者树与数组的对应关系 外部节点的数目为n,LowExt代表最底层的外部节点数目 ;offset代表最底层外部节点之上的所有节点数目 。每一个外部节点L[i]所对应的内部节点B[p],i和p之间存在如下的关系: p = 北京大学信息学院 Page 65

赢者树的类定义 template<class T> class WinnerTree{ private: int MaxSize; //允许的最大选手数 int n; //当前大小 int LowExt; //最低层的外部节点数 int offset; //2s+1-1 int * B; //内部节点数组 T * L; //外部节点数组 void Play(int p, int lc, int rc, int(* winner)(T A[], int b, int c)); 北京大学信息学院 Page 66

赢者树的类定义(续) public: WinnerTree(int Treesize = MAX); ~WinnerTree(){delete [] B;} void Initialize(T A[], int size,int (*winner)(T A[], int b, int c)); //初始化赢者树 int Winner();//返回最终胜者的索引 void RePlay(int i, int(*winner)(T A[], int b, int c)); //位置i的外部选手改变后重构赢者树 }; 北京大学信息学院 Page 67

败方树 所谓败方树就是在选择 (比赛)树中,每个非叶结点均存放其两个子结点中的败方所对应叶子节点的索引值。 此外,还另加进一个结点,即结点B[0],以代表比赛的全局获胜者的索引值。 北京大学信息学院 Page 68

败方树比赛过程 将新进入树的结点与其父结点进行比赛 这样的比赛不断进行,直到结点B[1]处比完 把败者存放在父结点中 而把胜者再与上一级的父结点进行比赛 这样的比赛不断进行,直到结点B[1]处比完 把败者的索引放在结点B[1] 把胜者的索引放到结点B[0] 北京大学信息学院 Page 69

败方树示例(1) 北京大学信息学院 Page 70

败方树示例(2): L[4]节点15进入 后做重构 北京大学信息学院 Page 71

败方树 ADT template<class T> class LoserTree{ private: int MaxSize; //最大选手数 int n; //当前选手数 int LowExt; //最底层外部节点数 int offset; //最底层外部节点之上的节点总数 int * B; //赢者树数组,实际存放的是下标 T * L; //元素数组 void Play(int p, int lc, int rc, int(* winner)(T A[], int b, int c)); 北京大学信息学院 Page 72

败方树ADT(续) public: LoserTree(int Treesize = MAX); ~LoserTree(){delete [] B;} void Initialize(T A[], int size,int (*winner)(T A[], int b, int c), int(*loser)(T A[], int b, int c)); //初始化败方树 int Winner(); //返回最终胜者索引 //位置i的选手改变后重构败方树 void RePlay(int i, int(*winner)(T A[], int b, int c), int (*loser)(T A[], int b, int c));}; 北京大学信息学院 Page 73

败方树的实现 //构造函数 template<class T> LoserTree<T>::LoserTree(int TreeSize){ MaxSize = TreeSize; B = new int[MaxSize]; n = 0; } //析构函数 LoserTree<T>::~LoserTree(){ delete [] B; 北京大学信息学院 Page 74

败方树的实现(续1) //成员函数Winner,返回最终胜者的索引 //在败方树中这个索引存放在B[0]中 template<class T> int LoserTree<T>::Winner(){ return (n)?B[0]:0; } 北京大学信息学院 Page 75

败方树的实现(续2) //成员函数Initilalize负责初始化败方树 template<class T> void LoserTree<T>::Initialize(T A[], int size, int(*winner)(T A[], int b, int c), int(*loser)(T A[], int b, int c)) { //能否处理size个选手的数组a[] if(size > MaxSize || size < 2){ cout<<"Bad Input!"<<endl<<endl; return; } 北京大学信息学院 Page 76

败方树的实现(续3) //初始化成员变量 n = size; L = A; //计算s=2^log(n-1) int i,s;   //计算s=2^log(n-1) int i,s; for(s = 1; 2*s <= n-1; s+=s); LowExt = 2*(n-s); offset = 2*s-1; 北京大学信息学院 Page 77

败方树的实现(续4) //最底层外部结点的比赛 for(i = 2; i <= LowExt; i+=2) Play((offset+i)/2, i-1, i, winner, loser); //处理其余外部结点 if(n%2){//n为奇数,内部结点和外部结点比赛 //这里用L[LowExt+1]和它的父结点比赛 //因为此时它的父结点中存放的是 //其兄弟结点处的比赛胜者索引 Play(n/2, B[(n-1)/2], LowExt+1, winner, loser); i = LowExt+3; } else i = LowExt+2; 北京大学信息学院 Page 78

败方树的实现(续5) //剩余外部结点的比赛 for(; i<=n; i+=2) Play((i-LowExt+n-1)/2, i-1, i, winner, loser); } 北京大学信息学院 Page 79

败方树的实现(续6) //成员函数Play负责在内部结点B[p]处开始比赛 template<class T> void LoserTree<T>::Play(int p, int lc, int rc, int(* winner)(T A[], int b, int c), int(* loser)(T A[], int b, int c)){   B[p] = loser(L, lc, rc);//败者索引放在B[p]中 int temp1, temp2; temp1 = winner(L, lc, rc);//p处的胜者索引 北京大学信息学院 Page 80

败方树的实现(续7) while(p>1 && p%2){ //右孩子,需要沿路径继续向上比赛 //和B[p]的父结点所标识的外部结点相比较 //p的胜者和p的父结点比较,赢者暂存在temp2中 temp2 = winner(L, temp1, B[p/2]); //败者索引放入B[p/2] B[p/2] = loser(L, temp1, B[p/2]); temp1 = temp2; p/=2; }//while  北京大学信息学院 Page 81

败方树的实现(续8) //结束循环(B[p]是左孩子,或者B[1])之后, //在B[p]的父结点写入胜者索引 B[p/2] = temp1;   } 北京大学信息学院 Page 82

败方树的实现(续9) //成员函数RePlay负责选手i的值改变后重新开始比赛 template<class T> void LoserTree<T>::RePlay(int i, int (*winner)(T A[], int b, int c), int (*loser)(T A[], int b, int c)){ if(i <= 0 || i > n){ cout<<"Out of Bounds!"<<endl<<endl; return; } 北京大学信息学院 Page 83

败方树的实现(续10) int p; //确定父结点的位置 if(i <= LowExt) p = (i+offset)/2; else p = (i-LowExt+n-1)/2; //B[0]中始终保存胜者的索引 B[0] = winner(L, i, B[p]); //B[p]中保存败者的索引 B[p] = loser(L, i, B[p]); 北京大学信息学院 Page 84

败方树的实现(续11) //沿路径向上比赛 for(; (p/2)>=1; p/=2){ int temp;//临时存放赢者的索引 temp = winner(L,B[p/2], B[0]); B[p/2] = loser(L,B[p/2], B[0]); B[0] = temp; } 北京大学信息学院 Page 85

利用败方树的多路归并排序算法 //输入参数分别是: // lt-败方树,racer-最初的竞赛者, // bufferPool-缓冲池,f-输入/输出文件句柄数组 //这里输出文件句柄是f[0],输入文件句柄是f[1]到 //f[MAX],MAX为输入文件的数目 //NO_MEANING宏代表一个极大值 template <class T> void multiMerge(LoserTree<T> & lt, T * racer, Buffer<T> * bufferPool, FILE * * f){ int winner; //最终胜者索引 T read; //读出的数据置放在里面 北京大学信息学院 Page 86

利用败方树的多路归并排序算法(续1) //初始化败方树 lt.Initialize(racer, MAX, Winner, Loser);   //以下处理f[1]到f[MAX]所代表的 //MAX个输入顺串, //并把结果输出到f[0]所代表的输出顺串中 //取得最终胜者索引 winner = lt.Winner(); 北京大学信息学院 Page 87

利用败方树的多路归并排序算法(续2) while(racer[winner] != NO_MEANING){ //所有的输入顺串都已经处理完毕 //把胜者插入到输出缓冲区中 //输出缓冲区满,flush到磁盘文件去 if(bufferPool[0].isFull()) bufferPool[0].flush(f[0]); bufferPool[0].insert(racer[winner]); 北京大学信息学院 Page 88

利用败方树的多路归并排序算法(续3) //从输入缓冲区读入一个新的竞赛者 if(bufferPool[winner].isEmpty()==false) //输入缓冲区不为空 //从缓冲区读入值放进racer[winner] bufferPool[winner].read(racer[winner]); else{//输入缓冲区为空 if(!feof(f[winner])){ //如果对应的输入文件还有数据 //从输入文件读入一批数据到输入缓冲区 fillBuffer(f[winner], bufferPool[winner]); 北京大学信息学院 Page 89

利用败方树的多路归并排序算法(续4) //从缓冲区读数据放进racer[winner] bufferPool[winner].read(racer[winner]); } //if else{//对应的输入文件没有数据 //在racer[winner]位置放NO_MEANING racer[winner] = NO_MEANING; }//else 北京大学信息学院 Page 90

利用败方树的多路归并排序算法(续5) //把输出缓冲区中剩余的数据写进磁盘文件 bufferPool[0].flush(f[0]); } //重新进行比赛,取得胜者索引 lt.RePlay(winner, Winner<int>, Loser<int>); winner = lt.Winner(); }//while //把输出缓冲区中剩余的数据写进磁盘文件 bufferPool[0].flush(f[0]);  } 北京大学信息学院 Page 91

多路归并的效率 假设对k个顺串进行归并。 原始方法:找到每一个最小值的时间是(k),产生一个大小为n的顺串的总时间是 (kn) 败方树方法:初始化包含k个选手的败方树需要 (k)的时间;读入一个新值并重构败方树的时间为 (log k)。故产生一个大小为n的顺串的总时间为 (k+nlog k)。 北京大学信息学院 Page 92

最佳归并树 (a)访外总次数为(6+13+25+8+9+2+14+7+10)×2×2=376 (b)外存读/写块的次数为(2+6+7)×3×2+(13+14)×2×2+(8+9+10)×2×2+25×2=356 北京大学信息学院 Page 93

最佳归并树 如果在进行多路归并的时候,各初始顺串的长度不同,对外存扫描的次数,即执行时间会产生影响。 把所有初始顺串的块数作为树的叶结点,如果是K路归并则建立起一棵K-叉Huffman树。这样的一棵Huffman树就是最佳归并树。 通过最佳归并树进行多路归并可以使对外存的I/O降到最少,提高归并执行效率。 北京大学信息学院 Page 94

本章总结 主存和外存的主要区别 磁盘的物理结构和工作方式 外存文件组织 缓冲区和缓冲池 外排序思想 置换选择排序 选择树(赢者树和败方树) 多路归并的效率 北京大学信息学院 Page 95