置换选择排序实在树形选择排序的基础上的来的,她产生的归并段的长度是不同,。
置换选择排序的操作过程,可以查看书,这里只给出C++可运行成功代码,
注:这里也需要建立败者树,但这里建立败者树的过程和上一个败者树建立过程是不一样的,,也可以自己画图进行建立过程的推导
#include<iostream>
#include<vector>
using namespace std;
#define w 6
typedef int Losertree[w];
struct rcdnode{
int key;
int rnum;
};
typedef rcdnode Workarea[w];
void Select_mini(Losertree &ls,Workarea &wa,int q){//调整败者树,和上一个败者树的调整类似,但是这里加入了段号,先比较段号,
for(int 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 tem=q;
q=ls[t];
ls[t]=tem;
}
}
ls[0]=q;
}
void Construct_loser(Losertree &ls,Workarea &wa,int fi[]){
for(int i=0;i!=w;++i){
wa[i].key=wa[i].rnum=ls[i]=0;//工作区初始化
}
for(int i=w-1;i>=0;--i){//输入一个关键字
wa[i].key=fi[i];
wa[i].rnum=1;//段号为1
Select_mini(ls,wa,i);//调整败者树
}
}
void get_run(Losertree &ls,Workarea &wa,int fi[],vector<int> &vec,int &counts,int rc,int &rmax){
while(wa[ls[0]].rnum==rc){//同属于一个段,不需要切换到下一个段
int q=ls[0];
int minimax=wa[q].key;
vec.push_back(minimax);//涮选出一个关键字
++counts;
if(counts>=24){wa[q].rnum=rmax+1;wa[q].key=1000;}//我的记录一共24个,全部读取完之后,则只需要消化败者树中剩余未输出的元素
else{
wa[q].key=fi[counts]; //提取下一个关键字
if(wa[q].key<minimax){ //如果小于上一个涮选出的关键字,则它属于下一段
rmax=rc+1;
wa[q].rnum=rmax;
}
else{
wa[q].rnum=rc;//否则属于当前段
}
}
Select_mini(ls,wa,q);
}
}
void Replace_selection(Losertree &ls,Workarea &wa,int fi[],vector <int>&vec){
Construct_loser(ls,wa,fi);//初建败者树
int rc=1;//当前生成的初始化段的段号,
int rmax=1;//败者树中最大的段号
int counts=5;//我的记录直接放在数组中,所以需要一个指针来指示读取的位置
while(rc<=rmax){//rc=rmax+1的时候标志输入文件的置换排序已经完成
get_run(ls,wa,fi,vec,counts,rc,rmax);//求得一个初始化段
vec.push_back(-1);//-1作为一个段的结束,标志作用,
rc=wa[ls[0]].rnum;//设置下一个段的段号
}
}
int main()
{
int fi[24]={51,49,39,46,38,29,14,61,15,30,1,48,52,3,63,27,4,13,89,24,46,58,33,76};//待排输入文件
vector<int>vec;
Workarea wa;
Losertree ls;
Replace_selection(ls,wa,fi,vec);
for(vector<int>::iterator it=vec.begin();it!=vec.end();++it){//输出置换选择排序后得到的归并段
if(*it==-1){
cout<<endl;
}
else
cout<<*it<<" ";
}
return 0;
}