多路平衡归并
一般说来,如果初始归并段有m个,那么这样的二路归并树就有élog2mù+1层,要对数据进行élog2mù遍扫描。采用k路平衡归并时,则相应的归并树有élogkmù+1层,要对数据进行élogkmù遍扫描。
做内部归并时,在k个记录中选择最小者,需要顺序比较k-1次。每趟归并u个记录需要做(u-1)*(k-1)次比较,s趟归并总共需要的比较次数为:(其中U代表总的记录个数,k代表的是归并的路数 ,s=élog2mù 因为同层的归并是同时进行的)
s*(u-1)*(k-1)=élogkmù*(u-1)*(k-1)
=élog2mù*(u-1)* (k-1)/élog2kù
其中,élog2mù*(u-1)在初始归并段个数m与记录个数u一定时是常量,而(k-1)/élog2kù在k增大时趋于无穷大。因此,增大归并路数k,会使内部归并的时间增大。若k增大到一定的程度,就会抵消掉由于减少读写磁盘次数而赢得的时间。
为了改善上面的归并的效率,引入了败者树算法
败者树是一棵有k个叶结点的完全二叉树,叶子结点存储记录,非叶结点可由关键字和它对应的记录地址构成。为讨论方便起见,设非叶结点的结构为:关键字, 输入有序段的路号
对k个输入有序段进行k路平衡归并的方法如下:
(1) 取每个输入有序段的第一个记录作为败者树的叶子结点,建立初始败者树:两两叶结点进行比较,在双亲结点中记录比赛的败者(关键字较大者),而让胜者去参加更高一层的比赛,如此在根结点之上胜出的“冠军”是关键字最小者。 (2) 胜出的记录写至输出归并段,在对应的叶结点处,补充其输入有序段的下一个记录,若该有序段变空,则补充一个大关键字(比所有记录关键字都大,设为kmax)的虚记录。
(3) 调整败者树,选择新的关键字最小的记录:从补充记录的叶结点向上和双亲结点的关键字比较,败者留在该双亲结点,胜者继续向上,直至树根的双亲。
(4) 若胜出的记录关键字等于kmax,则归并结束;否则转(2)继续。
一般说来,如果初始归并段有m个,那么这样的二路归并树就有élog2mù+1层,要对数据进行élog2mù遍扫描。采用k路平衡归并时,则相应的归并树有élogkmù+1层,要对数据进行élogkmù遍扫描。
做内部归并时,在k个记录中选择最小者,需要顺序比较k-1次。每趟归并u个记录需要做(u-1)*(k-1)次比较,s趟归并总共需要的比较次数为:(其中U代表总的记录个数,k代表的是归并的路数 ,s=élog2mù 因为同层的归并是同时进行的)
s*(u-1)*(k-1)=élogkmù*(u-1)*(k-1)
=élog2mù*(u-1)* (k-1)/élog2kù
其中,élog2mù*(u-1)在初始归并段个数m与记录个数u一定时是常量,而(k-1)/élog2kù在k增大时趋于无穷大。因此,增大归并路数k,会使内部归并的时间增大。若k增大到一定的程度,就会抵消掉由于减少读写磁盘次数而赢得的时间。
为了改善上面的归并的效率,引入了败者树算法
败者树是一棵有k个叶结点的完全二叉树,叶子结点存储记录,非叶结点可由关键字和它对应的记录地址构成。为讨论方便起见,设非叶结点的结构为:关键字, 输入有序段的路号
对k个输入有序段进行k路平衡归并的方法如下:
(1) 取每个输入有序段的第一个记录作为败者树的叶子结点,建立初始败者树:两两叶结点进行比较,在双亲结点中记录比赛的败者(关键字较大者),而让胜者去参加更高一层的比赛,如此在根结点之上胜出的“冠军”是关键字最小者。 (2) 胜出的记录写至输出归并段,在对应的叶结点处,补充其输入有序段的下一个记录,若该有序段变空,则补充一个大关键字(比所有记录关键字都大,设为kmax)的虚记录。
(3) 调整败者树,选择新的关键字最小的记录:从补充记录的叶结点向上和双亲结点的关键字比较,败者留在该双亲结点,胜者继续向上,直至树根的双亲。
(4) 若胜出的记录关键字等于kmax,则归并结束;否则转(2)继续。
打开IDE
![](https://img-my.csdn.net/uploads/201303/18/1363588183_8515.png)
创建一个工程
声名如下
调用如下
运行如下
代码下载
![](https://img-my.csdn.net/uploads/201211/20/1353411028_9740.png)
声名如下
#include "stdafx.h"
using namespace std;
//K路平衡归并
#include<iostream>
#include<iomanip>
//初始归并段个数
const int k=5;
const int m=4;//初始归并段中最多关键字个数
const int MAXKEY=999;//段结束标志
//二维数组b起磁盘文件作用
int b[k][m]={{3,5,13,MAXKEY},{4,6,MAXKEY},
{2,8,MAXKEY},{1,11,MAXKEY},{9,12,MAXKEY}};
typedef int keyType;
typedef struct
{keyType key;}ExNode;
ExNode buff[k][m];//结构体二维数组
int ls[k],st[k];
void Merge(int k);
void Read_Buff(int i);
void CreateLoserTree(int ls[],int k);
void Adjust(int ls[],int j,int k);
//K路平衡归并实现算法
void Merge(int k)
{int q;
for(int i=0;i<k;i++) Read_Buff(i);
CreateLoserTree(ls,k);
q=ls[0];
while(buff[q][st[q]].key!=MAXKEY)
{cout<<setw(3)<<buff[q][st[q]].key;
++st[q];
int w=st[q];
if(st[w]==m) Read_Buff(w);
Adjust(ls,q,k);
q=ls[0];
}
}
//读取各归并段数据,并设置相关变量st[i]的算法实现
void Read_Buff(int i)
{for(int j=0;j<m;j++)
buff[i][j].key=b[i][j];
st[i]=0;
}
//重构败者树的算法实现
void Adjust(int ls[],int j,int k)
{int t=(j+k)/2;
while(t>0)
{if(ls[t]==-1) {ls[t]=j;return;}
if(buff[j][st[j]].key>buff[ls[t]][st[ls[t]]].key)
{int y=j;j=ls[t];ls[t]=y;}
t=t/2;
}
ls[0]=j;
}
//创建败者树的算法实现
void CreateLoserTree(int ls[],int k)
{for(int i=0;i<k;i++) ls[i]=-1;
for(int i=k-1;i>=0;i--) Adjust(ls,i,k);
}
调用如下
//K路平衡归并相关操作测试
void main()
{cout<<"运行结果:\n";
Merge(5);
cin.get();
}
运行如下
![](https://img-my.csdn.net/uploads/201211/20/1353411036_4286.png)
代码下载