计算机存储器

外存储器特点

优点:永久存储能力、便携性

缺点:访问时间长

原则:尽量减少访问外存次数

外存数据访问方式

分为定位和存取两个阶段

外存被划为长度固定的存储空间

外存的数据访问以块为单位进行,从而减少外存的定位次数,进而减少外存读写的时间耗费

文件组织与管理

文件是存储在外存上的数据结构,由大量性质相同的记录组成的集合,记录是具有独立逻辑意义的数据块,是基本的数据单位

  • 按记录类型分

    • 操作系统文件

      一组连续的字符序列,没有明显结构

    • 数据库文件

      有结构的记录集合,每条记录都由一个或多个数据项组成,每个数据项是不可再分的基本数据单元

  • 按记录信息的长度分

    • 定长文件

    • 不定长文件

文件组织

操作系统以文件的方式组织数据,完成文件的逻辑结构到外存的物理结构的映射

  • 文件组织逻辑

    定长记录、变长记录和按关键码存取的记录

  • 文件物理结构

    顺序文件、散列文件、索引文件、倒排文件

C++文件流

文件流是以外存文件为输入输出的对象的数据流

包括istream,ostream,iostream和fstream,ifstream,ofstream

外排序

将外存中的数据文件划分为若干段,每次把一段读入内存并用内排序的方式进行排序

这些已排序的段或子文件称为顺串或归并段

将顺串写回外存,让出内存空间,然后处理其他未排序的段

都处理完后将顺串归并

  • 置换选择排序:把外存文件初始化为尽可能长的有序顺串集
  • 归并排序:把顺串集合逐趟归并排序,形成全局有序的外存文件

时间组成

  • 产生初始顺串的内排序所需时间
  • 初始化顺串和归并过程所需的读写时间
  • 内部归并所需要的时间

减少外存信息的读写次数是提高外排序效率的关键

置换选择排序

目的

将文件生成若干初始顺串(顺串越长越好,个数越少越好)

实现

借助在RAM中的堆来完成

  1. 初始化最小堆:提高RAM中的排序效率

    • 从缓冲区读M个记录放到数组RAM中
    • 设置堆尾标志:LAST=M-1
    • 建立一个最小值堆
  2. 重复以下步骤,直到堆空(结束条件)(即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 ⌈log2​m⌉+1,进行 ⌈ log ⁡ 2 m ⌉ \lceil\log_{2}m\rceil ⌈log2​m⌉遍扫描

需要两个输入缓冲区,一个输出缓冲区

k路归并

k路归并,每次对k个串进行扫描,归并趟数为 [ log ⁡ k m ] [\log_{k}m] [logk​m]

需要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=⌈log2​n⌉−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)/2​i≤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 数据结构与算法——外排序相关推荐

  1. 数据结构与算法(Python)【PKU MOOC】

    数据结构与算法(Python) 一. Python数据类型的性能 1.list 列表 列表list所包含的方法 #1 添加: list.append(a_new_element) #在列表末尾添加新的 ...

  2. 北京大学数据结构与算法视频下载

    数据结构与算法视频下载 北京大学张铭老师 视频下载 [转载] 第一讲 第1章 概论--1(概念.逻辑结构.存储) http://db.pku.edu.cn/mzhang/ds/media/1_intr ...

  3. 买什么数据结构与算法,这里有:动态图解十大经典排序算法(含JAVA代码实现)

    上篇的动图数据结构反响不错,这次来个动图排序算法大全.数据结构与算法,齐了. 几张动态图捋清Java常用数据结构及其设计原理 本文将采取动态图+文字描述+正确的java代码实现来讲解以下十大排序算法: ...

  4. 数据结构与算法专题——第一题 Bitmap算法

    在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在定位查找场景上具有O(1)的常量时间,多么的简洁优美, 但是在特定的场合下: ①:对10亿个不重复的整数进行排序. ②:找出1 ...

  5. 循环首次适应算法_数据结构与算法之2——排序问题

    排序真的是数据结构与算法中的重中之重啊,无论是对编程能力的提升,以后工作后的应用,或者是应对面试的时候都是经常需要用到的.基本的几个经典排序一定要做到滚瓜烂熟,能够做到给你一个具体的排序算法题,一定能 ...

  6. 基础数据结构和算法概念

    本文涉及更多的是概念,代码部分请参考之前写过的 2 篇博客 排序算法 基于Javascript 基本数据结构和查找算法 本文主要是基础的数据结构和算法概念,可能部分地方会涉及更高级的算法和算法,具体内 ...

  7. 数据结构与算法之排序算法

    数据结构与算法之排序算法 排序算法的介绍 ​ 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排序的过程. 排序的分类 1)内部排序:指将需要处理的数据都加载到内部 ...

  8. 数据结构与算法【Java】05---排序算法总结

    前言 数据 data 结构(structure)是一门 研究组织数据方式的学科,有了编程语言也就有了数据结构.学好数据结构才可以编写出更加漂亮,更加有效率的代码. 要学习好数据结构就要多多考虑如何将生 ...

  9. 【尚硅谷|韩顺平】数据结构和算法

    文章目录 前言: 数据结构和算法 数据结构和算法的概述 数据结构和和算法的关系 数据结构 线性结构和非线性结构 非线性结构 稀疏 sparsearray 数组 基本介绍: 稀疏数组的处理方法是: 应用 ...

最新文章

  1. 特殊用户邮箱附件大小设置
  2. Android Studio 如何导出和导入自己的常用设置,避免重复制造轮子。加快开发速度...
  3. 排序 -> 快速排序
  4. juniper *** LT2P
  5. Java 下的函数对象
  6. 【剑指offer】题目20 顺时针打印矩阵
  7. Oracle 中列出当前年所有日期和当前月所有日期
  8. 数字调制解调—扩频通信和伪码同步
  9. python下载安装教程(官网)
  10. servlet生成验证码和点击刷新验证码
  11. 阿里云服务器如何使用?阿里云服务器入门使用教程
  12. 华为充电协议_华为推出超级快充多协议充电器,支持65W USB PD快充输出
  13. VVIC搜款网平台API接口
  14. mysql57配置教程
  15. 盲子强巴(连载)二、
  16. 计算机启动显示安装程序正在启动服务,安装程序正在启动服务需要多久
  17. 大数据学习计划【2019经典不断更新】
  18. python版FlappyBird代码解析
  19. hash碰撞处理方法
  20. 台式计算机32位和64位的区别,电脑系统32位和64位有哪些区别 32位和64位是什么意思 【详解】...

热门文章

  1. 应该是史上最全最新Java和Android面试题目(自己总结和收集的)
  2. WARNING: WinPcap is now deprecated (not maintained). Please use Npcap instead
  3. Notepad用html怎么选颜色,Notepad++如何更改选中文字的颜色或背景色
  4. Eclipse之GBK 编码
  5. 机械行业在SEM百度竞价中如何推广?
  6. ​智能交通简介——效益和实例
  7. 人工智能行业前景如何?人工智能未来发展方向
  8. 面试官:MySQL是如何解决幻读的?
  9. 3A认证系统 环境搭建,freeradius + mysql + daloradius 时间:2018.2.2
  10. 幻灯片制作软件Movavi Slideshow Maker mac