外排序 & 败者树 & 多路归并-学习

来来来,根据这篇文章,学一下败者树吧:

http://blog.csdn.net/whz_zb/article/details/7425152

一、胜者树

胜者树的一个优点是,如果一个选手的值改变了,可以很容易地修改这棵胜者树。只需要沿着从该结点到根结点的路径修改这棵二叉树,而不必改变其他比赛的结果。

二、败者树

败者树是胜者树的一种变体。在败者树中,用父结点记录其左右子结点进行比赛的败者,而让胜者参加下一轮的比赛。败者树的根结点记录的是败者,需要加一个结点来记录整个比赛的胜利者。采用败者树可以简化重构的过程。

败者树 多路平衡归并外部排序

一 外部排序的基本思路

假设有一个72KB的文件,其中存储了18K个整数,磁盘中物理块的大小为4KB,将文件分成18组,每组刚好4KB。

首先通过18次内部排序,把18组数据排好序,得到初始的18个归并段R1~R18,每个归并段有1024个整数。

然后对这18个归并段使用4路平衡归并排序。

第1次归并:产生5个归并段
R11   R12    R13    R14    R15
其中
R11是由{R1,R2,R3,R4}中的数据合并而来
R12是由{R5,R6,R7,R8}中的数据合并而来
R13是由{R9,R10,R11,R12}中的数据合并而来
R14是由{R13,R14,R15,R16}中的数据合并而来
R15是由{R17,R18}中的数据合并而来
把这5个归并段的数据写入5个文件。

类推,下略。

二 使用败者树加快合并排序

外部排序最耗时间的操作时磁盘读写,对于有m个初始归并段,k路平衡的归并排序,磁盘读写次数为

|logkm|,可见增大k的值可以减少磁盘读写的次数,但增大k的值也会带来负面效应,即进行k路合并

的时候会增加算法复杂度。

如果使用败者树,可以在O(logk)的复杂度下得到最小的数,算法复杂度将为O((n-1)*logk), 对于外部排序这种数据量超大的排序来说,这是一个不小的提高。

时间: 2024-10-06 00:45:36

外排序 & 败者树 & 多路归并-学习的相关文章

外排序   败者树   多路归并

一.外排序 排序按数据存在的位置不同分为内排序和外排序 内排序:数据都在内存中,选择合适的排序方法对数据进行排序,比如选择排序.快速排序等 衡量内排序的效率是数据的比较次数 外排序:数据无法全部加载到内存中,只能不断在外部存储器和内存中进行交换完成排序 衡量外排序的效率是内存与外村的交换次数 外排序是针对大文件的数据排序,内存中无法加载这个大文件,把这个文件分为k个小文件,分别排序后合并 http://blog.csdn.net/msdnwolaile/article/details/52084

C++ 模板实现败者树,进行多路归并

项目需要实现一个败者树,今天研究了一下,附上实现代码. 几点说明: 1. 败者树思想及实现参考这里:http://www.cnblogs.com/benjamin-t/p/3325401.html 2. 多路归并中的“多路”的容器使用的是C语言数组 + 数组长度的实现(即 const ContainerType* ways, size_t num ),而没有用STL中的容器,这是因为项目需要如此,日后再改成STL容器: 3. _losers 存储下标,用的是 int 类型,还需要修改.程序中其他

数据结构:外排序-多路归并

外排序 外排序问题的出现,主要是因为内存不够.当需要排序的数据量过多,以至于无法一次性把所有的数据都放入内存,这导致了外排序问题的出现.解决大数据量排序的方法是:先分块排序,后进行块合并. 外排序步骤 把原数据分成几段读入内存,以至于每一块都可以完整的在内存中进行排序,排序好后,写入外部存储设备. 归并已排序好的数据块. 这就是归并排序在外排序中的应用. 对每块数据进行排序,可以使用各种内排序方法:快速排序.归并排序.堆排序等.这个比较简单,下面模拟一个对排序好的数据块进行归并的过程. #inc

算法-排序(1)k路平衡归并与败者树

const int MaxValue=999; //根据实际情况选择最大值 void kwaymerge(Element *r,int k){ int i,q; r=new Element[k]; //在败者树中的k个记录 int *key=new int[k+1]; //k个排序码和建树单元key[k] int *loser=new int[k]; //k-1个败者和冠军loser[0] for(i=0; i<k; i++){ //从k个归并段输入第一个记录及其排序码 InputRecord(

多路归并排序之败者树

#include<iostream> #include<iomanip> #define M 4 using namespace std; class LoserTree { private: // 调整K为2的整数次幂 int round(int k) { if(k&(k-1)!=0) { int i=0; for(i=31;i>=0;i--) { if(((1<<i)&k)!=0) { cout<<i<<endl; br

堆排序、胜者树、败者树,孰优孰劣?

在顺序存储结构中,堆排序是一种非常不错的高级选择排序算法,普通情况和最差情况下都可以将时间复杂度控制在O(n * logn). 堆排序可以用在顺序存储结构,是因为完全二叉树的一种独特性质.而这里还要先提一下满二叉树. 啥叫满二叉树?满二叉树是这样一种二叉树,它的每一层都是"满"的,设根部为第0层,则每一层都有2^n个节点.所有节点的度数要么是2,要么是0(叶子). 那完全二叉树呢?我们首先做出如下规定,即对二叉树中的节点,按从根部到叶子.每层从左到右递增的编号:如果某棵树,其所有节点的

排序(二)键索引、桶排序、位示图、败者树等

排序(二) 以上排序算法都有一个性质:在排序的最终结果中,各元素的次序依赖于它们之间的比较.我们把这类排序算法称为比较排序. 任何比较排序的时间复杂度的下界是nlgn. 以下排序算法是用运算而不是比较来确定排序顺序的.因此下界nlgn对它们是不适用的. 键索引计数法(计数排序) 计数排序假设n个输入元素中的每一个都是在0到k区间的一个整数,其中k为某个整数. 思想:对每一个输入元素x,确定小于x的元素个数.利用这一信息,就可以直接把x放到它在输出数组中的位置了. 例如: 学生被分为若干组,标号为

外部排序---置换选择+败者树

当需要对一个大文件进行排序时,计算机内存可能不够一次性装入所有数据,解决办法是归并.归并的大概做法是将大文件分为若干段,依次读入内存进行排序,排序后再重新写入硬盘.这些排好序的片段成为顺串.然后对这些顺串进行逐躺归并,使归并段逐渐由小变大,最终使整个文件有序.要使用归并就得考虑两个问题,一个是如何生成顺串,一个是如何对顺串进行归并. 置换选择算法 先考虑如何生成顺串.我们知道,减少顺串的数量可以降低归并的次数,而在文件大小固定的情况下,要减少顺串的数量,就要增大单个顺串的长度.如果使用内部排序生

(转)败者树 和 胜者树---数组实现

转自:http://blog.csdn.net/sqx2011/article/details/8241734 胜者树和败者树都是完全二叉树,是树形选择排序的一种变型.每个叶子结点相当于一个选手,每个中间结点相当于一场比赛,每一层相当于一轮比赛. 不同的是,胜者树的中间结点记录的是胜者的标号:而败者树的中间结点记录的败者的标号. 胜者树与败者树可以在log(n)的时间内找到最值.任何一个叶子结点的值改变后,利用中间结点的信息,还是能够快速地找到最值.在k路归并排序中经常用到. 一.胜者树 胜者树