PKU 数据结构与算法——外排序
计算机存储器
外存储器特点
优点:永久存储能力、便携性
缺点:访问时间长
原则:尽量减少访问外存次数
外存数据访问方式
分为定位和存取两个阶段
外存被划为长度固定的存储空间
外存的数据访问以块为单位进行,从而减少外存的定位次数,进而减少外存读写的时间耗费
文件组织与管理
文件是存储在外存上的数据结构,由大量性质相同的记录组成的集合,记录是具有独立逻辑意义的数据块,是基本的数据单位
按记录类型分
操作系统文件
一组连续的字符序列,没有明显结构
数据库文件
有结构的记录集合,每条记录都由一个或多个数据项组成,每个数据项是不可再分的基本数据单元
按记录信息的长度分
定长文件
不定长文件
文件组织
操作系统以文件的方式组织数据,完成文件的逻辑结构到外存的物理结构的映射
文件组织逻辑
定长记录、变长记录和按关键码存取的记录
文件物理结构
顺序文件、散列文件、索引文件、倒排文件
C++文件流
文件流是以外存文件为输入输出的对象的数据流
包括istream,ostream,iostream和fstream,ifstream,ofstream
外排序
将外存中的数据文件划分为若干段,每次把一段读入内存并用内排序的方式进行排序
这些已排序的段或子文件称为顺串或归并段
将顺串写回外存,让出内存空间,然后处理其他未排序的段
都处理完后将顺串归并
- 置换选择排序:把外存文件初始化为尽可能长的有序顺串集
- 归并排序:把顺串集合逐趟归并排序,形成全局有序的外存文件
时间组成
- 产生初始顺串的内排序所需时间
- 初始化顺串和归并过程所需的读写时间
- 内部归并所需要的时间
减少外存信息的读写次数是提高外排序效率的关键
置换选择排序
目的
将文件生成若干初始顺串(顺串越长越好,个数越少越好)
实现
借助在RAM中的堆来完成
- 初始化最小堆:提高RAM中的排序效率
- 从缓冲区读M个记录放到数组RAM中
- 设置堆尾标志:LAST=M-1
- 建立一个最小值堆
- 重复以下步骤,直到堆空(结束条件)(即LAST<0)
- 把具有最小关键码值的记录(根结点)送到输出缓冲区
- 设R是输入缓冲区的下一条记录
- 如果R的关键码不小于刚输出的关键码值,则把R放到根结点
- 否则使用数组中的LAST位置的记录代替根结点,然后把R放到LAST位置(等待下一顺串处理),设置LAST=LAST-1
- 重新排列堆,筛出根结点
大小是M的堆,最小顺串的长度为M的记录
- 至少原来堆中的那些记录将成为顺串的一部分
- 最好情况下一次就可能把整个文件生成为一个顺串
- 平均长度为2M
算法
//A是从外存读入n个元素后所存放的数组
template <class Elem>
void ReplacementSelection(Elem * A, int n, const char * in, const char * out)
{Elem mval;//存放最小堆的最小值Elem r;//存放从输入缓冲区中读入的元素FILE * iptF;//输入文件句柄FILE * optF;//输出文件句柄Buffer<Elem> input;//输入 bufferBuffer<Elem> output;// 输出bufferinitFiles(inputFile, outputFile, in, out);//初始化输入输出文件initMinHeapArry(inputFile, n, A);//初始化堆的数据,读入n个数据 MinHeap<Elem> H(A, n, n);//建立最小值堆 initInputBuffer(input, inputFile);//初始化inputbuffer,读入部分数据 for(int last =n-1; last >= 0;){mval = H.heapArray[0];//堆的最小值sendToOutputBuffer(input,output,iptF,optF, mval);input.read(r);//从输入缓冲区读入一个记录if(!less(r, mval)) H.heapArray[0] = r;else//否则用last位置记录代替根结点,把r放到last {H.heapArray[0] = H.heapArray[last];H.heapArray[last] = r;H.setSize(last);last--;} if (last!=0) H.SiftDown(0);//堆调整 }endUp(output,inputFile,outputFile);//处理输出缓冲区
}
归并排序
归并性质
二路归并
合并树高 ⌈ log 2 m ⌉ + 1 \lceil\log_{2}m\rceil+1 ⌈log2m⌉+1,进行 ⌈ log 2 m ⌉ \lceil\log_{2}m\rceil ⌈log2m⌉遍扫描
需要两个输入缓冲区,一个输出缓冲区
k路归并
k路归并,每次对k个串进行扫描,归并趟数为 [ log k m ] [\log_{k}m] [logkm]
需要k个输入缓冲区,一个输出缓冲区
最佳归并树
归并顺序的安排影响读写次数,把初始顺串的长度作为权其实质就是Huffman树最优化的问题
过程
把所有初始顺串的块数作为树的叶结点,如果是k路归并则建立其一棵k-叉Huffman树,这样的一棵Huffman树就是最佳归并树
多路归并树
在做k路归并时每次都需要比K-1次才能找出所需要的记录,代价较大,想要提高在k个归并串的当前值中找到最小值的效率
赢者树
用完全二叉树作为存储结构
叶结点用数组L[1……n]表示,内部结点用数组B[1……n-1]表示
数组B中存放的实际是数组L的索引
内部结点记录的是赢者
结点的关系
n路归并,赢者树具有2n-1个结点
外部结点数为n,内部结点数为n-1,比赛树深度 s = ⌈ log 2 n ⌉ − 1 s=\lceil\log_{2}n\rceil-1 s=⌈log2n⌉−1
最底层最左端内部结点的编号为2s
最低层的内部结点数为n-2s
最底层的外部结点数为最底层内部结点数的2倍,即 L o w E x t = 2 ( n − 2 s ) LowExt=2(n-2^s) LowExt=2(n−2s)
最底层外部结点之上的所有结点的结点数目(offset)有 o f f s e t = 2 s + 1 − 1 offset=2^{s+1}-1 offset=2s+1−1
外部结点L[i]与内部父节点B[p]的关系表示如下
{ ( i + o f f s e t ) / 2 i ≤ L o w E x t ( i − L o w E x t + n − 1 ) / 2 i > L o w E x t \begin{cases}(i+offset)/2 &i\le LowExt\\(i-LowExt+n-1)/2 &i>LowExt \end{cases} {(i+offset)/2(i−LowExt+n−1)/2i≤LowExti>LowExt
赢者树的特点
通过比较两个选手的分数确定一场比赛的赢家
从树的最底层开始,每两个树叶之间进行比赛,输的选手被淘汰,赢的继续向上进行比赛,树根记录了整个比赛的胜者
如果选手L[i]的分值改变,可以修改这棵赢者树
沿着从L[i]到根结点的路径,和兄弟结点的值进行比较,根据比赛结构修改二叉树结点的值,而不必修改其它部分的比赛结果
败者树
结点记录的是败者,在根结点上再增加一个根结点B[0]用来记录最后一次的赢者
败者树重构时只需要和路径上的结点比,不需要和兄弟结点比,简化了重构过程
比赛过程
将新的进入树的结点与其父结点进行比赛
把败者存放在父结点中,把胜者再与上一级的父结点进行比赛
比赛不断进行,直到结点B[1]
把败者的索引放在结点B[1],把胜者的索引放到结点B[0]
算法
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), int(*loser)(T A[], int b, int c));// 在内部结点从右分支向上比赛
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();// 返回最终胜者索引void RePlay(int i, int(*winner)(T A[], int b, int c), int (*loser)(T A[], int b, int c));// 重构败者树
};
初始化败者树
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))
{int i,s;n = size;// 初始化成员变量L = A;for (s = 1; 2*s <= n-1; s += s);//计算倒数第2层节点数LowExt = 2*(n-s);offset = 2*s-1;for (i = 2; i <= LowExt; i += 2)// 最底层外部结点比赛Play((offset+i)/2, i-1, i, winner, loser);// 处理其余外部结点if (n%2)//n为奇数,内部结点和外部结点比一次{// 暂存在父中的左胜者与外部右子结点比Play(n/2, B[(n-1)], LowExt+1, winner, loser); i = LowExt+3;}else i = LowExt+2; for (; i <= n; i += 2)// 剩余外部结点的比赛Play((i-LowExt+n-1)/2, i-1, i, winner, loser);
}
生成败者树
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); while (p>1 && p%2){//p为奇数向上比赛temp2 = winner(L, temp1, B[p/2]);//胜者与父比较B[p/2] = loser(L, temp1, B[p/2]);//败者留下temp1 = temp2;//胜者放入temp1p/=2;//p向上指向父结点}B[p/2] = temp1;//B[p]是左孩子或者p=1
}
重构败者树
void LoserTree<T>::RePlay(int i, int (*winner)(T A[], int b, int c), int (*loser)(T A[], int b, int c))
{int p;//用于计算父结点索引的临时变量if (i <= LowExt)//确定父结点的位置p = (i+offset)/2;else p = (i-LowExt+n-1)/2;B[0] = winner(L, i, B[p]);// B[0]中保存胜者的索引B[p] = loser(L, i, B[p]);// B[p]中保存败者的索引 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;}
}
多路归并的效率
对k个顺串进行归并
- 原始方法:找到每一个最小值的时间是O(k),产生一个大小为n的顺串的总时间是O(kn)
- 败者树方法:初始化包含k个选手的败者树需要O(k),读入一个新值并重构败者树需要O(logk),产生一个大小为n的顺串的总时间是O(k+nlogk)
PKU 数据结构与算法——外排序相关推荐
- 数据结构与算法(Python)【PKU MOOC】
数据结构与算法(Python) 一. Python数据类型的性能 1.list 列表 列表list所包含的方法 #1 添加: list.append(a_new_element) #在列表末尾添加新的 ...
- 北京大学数据结构与算法视频下载
数据结构与算法视频下载 北京大学张铭老师 视频下载 [转载] 第一讲 第1章 概论--1(概念.逻辑结构.存储) http://db.pku.edu.cn/mzhang/ds/media/1_intr ...
- 买什么数据结构与算法,这里有:动态图解十大经典排序算法(含JAVA代码实现)
上篇的动图数据结构反响不错,这次来个动图排序算法大全.数据结构与算法,齐了. 几张动态图捋清Java常用数据结构及其设计原理 本文将采取动态图+文字描述+正确的java代码实现来讲解以下十大排序算法: ...
- 数据结构与算法专题——第一题 Bitmap算法
在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在定位查找场景上具有O(1)的常量时间,多么的简洁优美, 但是在特定的场合下: ①:对10亿个不重复的整数进行排序. ②:找出1 ...
- 循环首次适应算法_数据结构与算法之2——排序问题
排序真的是数据结构与算法中的重中之重啊,无论是对编程能力的提升,以后工作后的应用,或者是应对面试的时候都是经常需要用到的.基本的几个经典排序一定要做到滚瓜烂熟,能够做到给你一个具体的排序算法题,一定能 ...
- 基础数据结构和算法概念
本文涉及更多的是概念,代码部分请参考之前写过的 2 篇博客 排序算法 基于Javascript 基本数据结构和查找算法 本文主要是基础的数据结构和算法概念,可能部分地方会涉及更高级的算法和算法,具体内 ...
- 数据结构与算法之排序算法
数据结构与算法之排序算法 排序算法的介绍 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排序的过程. 排序的分类 1)内部排序:指将需要处理的数据都加载到内部 ...
- 数据结构与算法【Java】05---排序算法总结
前言 数据 data 结构(structure)是一门 研究组织数据方式的学科,有了编程语言也就有了数据结构.学好数据结构才可以编写出更加漂亮,更加有效率的代码. 要学习好数据结构就要多多考虑如何将生 ...
- 【尚硅谷|韩顺平】数据结构和算法
文章目录 前言: 数据结构和算法 数据结构和算法的概述 数据结构和和算法的关系 数据结构 线性结构和非线性结构 非线性结构 稀疏 sparsearray 数组 基本介绍: 稀疏数组的处理方法是: 应用 ...
最新文章
- 特殊用户邮箱附件大小设置
- Android Studio 如何导出和导入自己的常用设置,避免重复制造轮子。加快开发速度...
- 排序 -> 快速排序
- juniper *** LT2P
- Java 下的函数对象
- 【剑指offer】题目20 顺时针打印矩阵
- Oracle 中列出当前年所有日期和当前月所有日期
- 数字调制解调—扩频通信和伪码同步
- python下载安装教程(官网)
- servlet生成验证码和点击刷新验证码
- 阿里云服务器如何使用?阿里云服务器入门使用教程
- 华为充电协议_华为推出超级快充多协议充电器,支持65W USB PD快充输出
- VVIC搜款网平台API接口
- mysql57配置教程
- 盲子强巴(连载)二、
- 计算机启动显示安装程序正在启动服务,安装程序正在启动服务需要多久
- 大数据学习计划【2019经典不断更新】
- python版FlappyBird代码解析
- hash碰撞处理方法
- 台式计算机32位和64位的区别,电脑系统32位和64位有哪些区别 32位和64位是什么意思 【详解】...
热门文章
- 应该是史上最全最新Java和Android面试题目(自己总结和收集的)
- WARNING: WinPcap is now deprecated (not maintained). Please use Npcap instead
- Notepad用html怎么选颜色,Notepad++如何更改选中文字的颜色或背景色
- Eclipse之GBK 编码
- 机械行业在SEM百度竞价中如何推广?
- ​智能交通简介——效益和实例
- 人工智能行业前景如何?人工智能未来发展方向
- 面试官:MySQL是如何解决幻读的?
- 3A认证系统 环境搭建,freeradius + mysql + daloradius 时间:2018.2.2
- 幻灯片制作软件Movavi Slideshow Maker mac