置换-选择排序

来源:互联网 发布:颈椎按摩器 知乎 编辑:程序博客网 时间:2024/05/29 19:27

外部排序过程中,为了减少外存读写次数需要减小归并趟数(外部排序的过程中用到归并),归并趟数为:外部排序1(其中k为归并路数,n为归并段的个数)。增加k和减小n都可以达到减小归并趟数的目的。置换-选择排序就是一种减小n的、在外部排序中创建初始归并段时用到的算法。它可以让初始归并段的长度增减,从而减小初始归并段的段数(因为总的记录数是一定的)。

 

置换-选择排序是在树形选择排序的基础上得来的,它的特点是:在整个排序(得到初始归并段)的过程中,选择最小(或最大)关键值和输入、输出交叉或并行进行。它的主要思路是:用败者树从已经传递到内存中的记录中找到关键值最小(或最大)的记录,然后将此记录写入外存,再将外存中一个没有排序过的记录传递到内存(因为之前那个记录写入外存后已经给它空出内存),然后再用败者树的一次调整过程找到最小关键值记录(这个调整过程中需要注意:比已经写入本初始归并段的记录关键值小的记录不能参见筛选,它要等到本初始段结束,下一个初始段中才可以进行筛选),再将此最小关键值记录调出,再调入新的记录.......依此进行指导所有记录已经排序过。内存中的记录就是所用败者树的叶子节点。

 

假设初始待排序文件为FI,初始归并段文件为输出文件FO,内存工作区为WA,FO与WA的初始状态为空,并假设内存工作去WA的容量可容纳w个记录,则置换-选择排序的操作的过程为:

   (1)、从FI输入w个记录到工作区WA。

   (2)、从WA中选出其中关键字最小的记录,记为MINIMAX记录。

   (3)、将MINIMAX记录输出到FO中去。

   (4)、若FI不为空,则从FI输入下一个记录到WA中。

  (5)、从WA中所有关键字比MINIMAX记录关键字大的记录中选出最小关键字记录,作为新的MINIMAX记录。

   (6)、重复(3)~(5),直至WA中选不出新的MINIMAX记录为止,由此得到一个初始归并段,输出一个归并段的结束标记到FO中去。

   (7)、重复(2)~(6),直至WA为空。由此得到全部归并段。

 

在WA中选择MINIMAX记录的过程利用“败者树”来实现。就置换-排序中败者树的实现细节这里加以说明。(1)、内存空间中的记录做为败者树的外部节点,而败者树中根节点的双亲节点指示工作区中关键字最小的记录。(2)、为了便于选择MINIMAX记录,为每个记录附设一个所在归并段的序号,在进行关键字的比较时,先比较段号,段号小的为胜者;段号相同的则关键字小的为胜者;(3)、败者树的建立可以从设工作区中所有记录的段号为0开始,让后从FI逐个输入w个记录到工作区时,自下而上调整败者树,由于这些记录的段号为1,则他们对于0段的记录来说均为败者,从而逐个填充到败者树的各节点中去。

 

下面是几个置换排序中用到的函数(伪代码):

typedef struct

{

    RcdTyperec;    //记录

    KetType key;   //从记录中抽取的关键字

    intrnum;      //所属归并段的段号

}RcNode,WorkArea[w];    //内存工作区,容量为w

 

typedef int LoserTree[w]; 

//在败者树ls和内存工作区wa上用置换-选择排序求初始归并段,fi为输入文件指针,fo为输出文件指针,

//两个文件均已打开

void Replace_Selection(LoserTree &ls,WorkArea&wa,FILE* fi,FILE* fo)

{

     Construct_loser(ls,wa);  //初建败者树

      rc=rmax=1; //rc指示当前生成的初始归并段的段号,rmax指示wa中关键字所属归初始归并段的最大

                //段号,在此过程中,rmax比rc最多大1

      while(rc<=rmax)  //rc=rmax+1标志着输入文件的置换-选择排序已经完成

     {

           get_run(ls,wa);  //求得一个初始归并段

           fwrite(&RUNEND_SYMBOL,sizeof(structRcdType),1,fo);//将段结束标记写入输出文件

           rc=wa[ls[0]].rnum;

      }

}

 

//求得一个初始归并段,fi为输入文件指针,fo为输出文件指针

void get_run(LoserTree &ls,WorkArea&wa)

{

     while(wa[ls[0]].rnum==rc)

      {

           q=ls[0];//选得的MINIMAX记录属当前段时,q指示MINIMAX记录在wa中的记录

           minimax=wa[q].key;

           fwrite(&wa[q].rec,sizeof(RcdType),1,fo);

           if(feof(fi)) //若输入文件结束,虚设记录(属rmax+1段)

            {

                 wa[q].rnum=rmax+1;

                 wa[q].key=MAXKEY;

            }

           else

           {

                 fread(&wa[q].rec,sizeof(RcdType),1,fi);

                 wa[q].key=wa[q].rec.key;  //提取关键字

                 if(wa[q].key<minimax)  //新读入的记录属于下一段

                  {

                       rmax=rc+1;

                       wa[q].rnum=rmax;

                  }

                   else   //新都如的记录属于当前段

                       wa[q].rnum=rc;

            }

            Select_MiniMax(ls,wa,q);  //选择新的MINIMAX记录

      }

}

 

//从wa[q]起到败者树的根比较选择MINIMAX记录,并有q指示它所在的归并段

void Select_MiniMax(LoserTree &ls,WorkAreawa,int q)

{

     for(t=(w+q)/2,p=ls[t];t>0;t=t/2,p=ls[t])

          if(wa[p].rnum<wa[q].rnum||wa[p].rnum==wa[q].rnum&&wa[p].key<wa[q].key)

           {

               int temp=ls[t];

                ls[t]=q;

               q=temp;   //q指示新的胜利者

           }

      ls[0]=q;

}

 

//输入w个记录到内存工作区wa,建得败者树ls,选出关键字最小的记录并由s指示器在wa中的位置

void Construct_Loser(LoserTree&ls,WorkArea&wa) 

{

      for(i=0;i<w;++i)

          wa[i].rnum=wa[i].key=ls[i]=0;  //工作区初始化

      for(i=w-1;i>=0;--i)

     {

           fread(&wa[i].rec,sizeof(RcdType),1,fi); //输入一个记录

           wa[i].key=wa[i].rec.key;  //提取关键字

            wa[i].rnum=1;  //其段号为1

           Select_MiniMax(ls,wa,i);  //调整败者

      }

}

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 有限公司法人变更后债务怎么办 有限公司法人跑路债务怎么办 网上买票身份信息待核验怎么办 微信买票身份核验失败怎么办 买高铁票待核验怎么办 网上购票身份待核验怎么办 b站稿件版权原因怎么办 已离职老板打电话说账有问题怎么办 开到应急刹车道怎么办 自动挡的车刹车失灵怎么办 自动挡的车如果刹车失灵怎么办 手动挡汽车刹车失灵怎么办 车辆没有年检出了交通事故怎么办 跟着大货车闯了红灯怎么办 在万家金服买的电子产品坏了怎么办 汽车被油笔画了怎么办? 挂到别人车跑了怎么办 浪琴手表保修卡掉了怎么办 事故车辆维修和报废怎么办 4.2货车拉缸了怎么办 工作中与同事发生矛盾怎么办 和领导关系闹僵怎么办 内倒窗户卡住了怎么办 支付宝存在安全风险怎么办 地铁车站空调坏了怎么办 面试防汛值班发生灾情你怎么办 怀孕上班路途太远怎么办 硕士错过校招应该怎么办 收银员收多了钱怎么办 商铺贷款批不了怎么办 铁路局的门面乱收房租怎么办 酒店夜审房费多过怎么办 夜审房价录多了怎么办 做工地拿不到钱怎么办 赢了官司拿不到钱怎么办 工地上拿不到钱怎么办 做了工拿不到钱怎么办 高速公路上车没油了怎么办 高铁乘务员年龄大了怎么办 总公司跑路了分公司怎么办 坐车久了耳朵懵怎么办