多路归并排序

多路归并排序

多路归并排序算法在常见数据结构书中都有涉及。从2路到多路(k路),增大k可以减少外存信息读写时间,但k个归并段中选取最小的记录需要比较k-1次,为得到u个记录的一个有序段共需要(u-1)(k-1)次,若归并趟数为s次,那么对n个记录的文件进行外排时,内部归并过程中进行的总的比较次数为s(n-1)(k-1),若共有m个归并段,则s=logkm,所以总的比较次数为: (向上取整)(logkm)(k-1)(n-1)=(向上取整)(log2m/log2k)(k-1)(n-1),而(k-1)/log2k随k增而增因此内部归并时间随k增长而增长了,抵消了外存读写减少的时间,这样做不行,由此引出了“败者树”tree of loser的使用。在内部归并过程中利用败者树将k个归并段中选取最小记录比较的次数降为(向上取整)(log2k)次使总比较次数为(向上取整)(log2m)(n-1),与k无关。

败者树

叶子节点记录k个段中的最小数据,然后两两进行比赛。败者树是在双亲节点中记录下刚刚进行完的这场比赛的败者,让胜者去参加更高一层的比赛。决赛,根节点记录输者,所以需要重建一个新的根节点,记录胜者(如下图节点0)。

示例:我们这里以四路归并为例,假设每个归并段已经在输入缓冲区如下图。

每路的第一个元素为胜利树的叶子节点,(5,7)比较出5胜出7失败成为其根节点,(29,9)比较9胜出29失败成为其节点,胜者(5,9)进行下次的比赛9失败成为其根节点5胜出输出到输出缓冲区。由第一路归并段输出,所有将第一路归并段的第二个元素加到叶子节点如下图:

加入叶子节点16进行第二次的比较,跟胜利树一样,由于右子树叶子节点没有发生变化其右子树不用再继续比较。


K路归并排序的实现

[cpp]  view plain  copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define LEN 10          //最大归并段长  
  5. #define MINKEY -1     //默认全为正数  
  6. #define MAXKEY 100    //最大值,当一个段全部输出后的赋值  
  7.   
  8. struct Array  
  9. {  
  10.     int arr[LEN];  
  11.     int num;  
  12.     int pos;  
  13. }*A;  
  14.   
  15. int k,count;  
  16. int *LoserTree,*External;  
  17.   
  18. void Adjust(int s)  
  19. {  
  20.     int t=(s+k)/2;//ls[t]是b[s]的双亲结点的下标  
  21.     int temp;  
  22.     while(t>0)  
  23.     {  
  24.         if(External[s] > External[LoserTree[t]])  
  25.         {  
  26.             temp = s;  
  27.             s = LoserTree[t];  
  28.             LoserTree[t]=temp;  
  29.         }  
  30.         t=t/2;  
  31.     }  
  32.     LoserTree[0]=s;  
  33. }  
  34.   
  35. void CreateLoserTree()  
  36. {  
  37.     External[k]=MINKEY;  
  38.     int i;  
  39.     for(i=0;i<k;i++)LoserTree[i]=k;//设置ls中败者的初值,简化了败者树的建立过程,这样就可以直接通过(调整过程)来建立败者树。  
  40.     for(i=k-1;i>=0;i--)Adjust(i);  
  41. }  
  42.   
  43. void K_Merge()  
  44. {  
  45.     int i,p;  
  46.     //初始化External数组,用以接下来创建LoserTree  
  47.     for(i=0;i<k;i++)  
  48.     {  
  49.         p = A[i].pos;  
  50.         External[i]=A[i].arr[p];  
  51.         //cout<<External[i]<<",";  
  52.         A[i].pos++;  
  53.     }  
  54.     //创建LoserTree  
  55.     CreateLoserTree();  
  56.     int NO = 0;  
  57.     //输出最小值,并替代调整  
  58.     while(NO<count)  
  59.     {  
  60.         p=LoserTree[0];  
  61.         cout<<External[p]<<",";  
  62.         NO++;  
  63.         if(A[p].pos>=A[p].num)External[p]=MAXKEY;  
  64.         else   
  65.         {  
  66.             External[p]=A[p].arr[A[p].pos];  
  67.             A[p].pos++;  
  68.         }  
  69.         Adjust(p);  
  70.     }  
  71.     cout<<endl;  
  72. }  
  73.   
  74. int main()  
  75. {  
  76.     //freopen("in.txt","r",stdin);  
  77.   
  78.     int i,j;  
  79.     count=0;  
  80.     cin>>k;  
  81.     A=(Array *)malloc(sizeof(Array)*k);  
  82.     for(i=0;i<k;i++)  
  83.     {  
  84.         cin>>A[i].num;  
  85.         count=count+A[i].num;  
  86.         for(j=0;j<A[i].num;j++)  
  87.         {  
  88.             cin>>A[i].arr[j];  
  89.         }  
  90.         A[i].pos=0;  
  91.     }  
  92.     LoserTree=(int *)malloc(sizeof(int)*k);  
  93.     External=(int *)malloc(sizeof(int)*(k+1));  
  94.   
  95.     K_Merge();  
  96.     system("pause");  
  97.     return 0;  
  98. }  
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值