算法理论与分析实验.docx
《算法理论与分析实验.docx》由会员分享,可在线阅读,更多相关《算法理论与分析实验.docx(21页珍藏版)》请在冰豆网上搜索。
![算法理论与分析实验.docx](https://file1.bdocx.com/fileroot1/2022-12/17/579bacd6-fc49-49e9-be53-cd5f3ac5dc72/579bacd6-fc49-49e9-be53-cd5f3ac5dc721.gif)
算法理论与分析实验
实验一:
1、问题描述:
设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)循环赛一共进行n-1天。
用分治法实现。
2、算法描述:
按分治策略,将所有分为两半,n个选手可以通过n/2个选手设计的比赛日程表来决定。
递归地用一分为二的略对选手进行分割,直到只剩下两个选手。
对于n为奇数的情况可以虚拟多一个选手,使其编程n+1个选手的日程表,最然后忽略虚拟运动员参与的比赛。
对于分割时候n/2的情况也做特殊处理,前n/2轮比赛空选手与下一个未参赛的选手进行比赛。
伪代码如下:
voidtournament(intm)
{
if(m==1)
{
A[0][0]=1;
return;
}
elseif(isodd(m))//如果m为奇数,则m+1是偶数
{
tournament(m+1);//按照偶数个选手来求解
replaceVirtual(m+1);//然后把第m+1号虚选手置成0
return;
}
else//r如果m是偶数,
{
tournament(m/2);//分治,先安排第1组的m/2人比赛
makecopy(m);//合并,根据算法,构造左下、右下、右上、右下的矩阵
}
return;
}
//判断m的奇偶性
boolisodd(m)
{
Returnm&1;//m为奇数,返回1,m为偶数,返回0
}
/*makecopy:
当前有m位(偶数)选手,分成两组,每组由m/2位选手构成
由第一组的m/2位选手的安排来构成第二组的比赛安排,第一
组与第二组的比赛安排。
要区分m/2为奇数和偶数两种情况
*/
voidmakecopy(intm)
{
if(isodd(m/2))//m/2为奇数
copyodd(m/2);
else//m/2为偶数
copyeven(m/2);
}
/*copyeven:
m为偶数时用,由前1组的m位选手的安排,来构成第2组m位选手
的赛程安排,以及两组之间的比赛安排*/
voidcopyeven(intm)
{
if(isodd(m))return;
inti,j;
for(j=0;j{
for(i=0;i{
A[i+m][j]=A[i][j]+m;
}
}
for(j=m;j<2*m;j++)//两组间比赛的安排
{
for(i=0;i{
A[i][j]=A[i+m][j-m];//把左下角拷贝到右上角
}
for(i=m;i<2*m;i++)//3.对应的,第2组和第1组
{
A[i][j]=A[i-m][j-m];//把左上角拷贝到右下角
}
}
return;
}
/*copyodd:
m为奇数时用,由前1组的m位选手的安排,来构成第2组m位选手
的赛程安排,以及两组之间的比赛安排。
这时和m为偶数时的
处理有区别。
*/
voidcopyodd(intm)
{
inti,j;
for(j=0;j<=m;j++)//1.求第2组的安排(前m天)
{
for(i=0;i{
if(A[i][j]!
=0)
{
A[i+m][j]=A[i][j]+m;
}
else//特殊处理:
两个队各有一名选手有空,安排他们比赛
{
A[i+m][j]=i+1;
A[i][j]=i+m+1;
}
}
}
//安排两组选手之间的比赛(后m-1天)
for(i=0,j=m+1;j<2*m;j++)
{
A[i][j]=j+1;//2.1号选手的后m-1天比赛
A[(A[i][j]-1)][j]=i+1;//3.他的对手后m-1天的安排
}
//以下的取值要依赖于1号选手的安排,所以之前先安排1号的赛程
for(i=1;i{
for(j=m+1;j<2*m;j++)
{//2.观察得到的规则一:
向下m+1~2*m循环递增
A[i][j]=((A[i-1][j]+1)%m==0)?
A[i-1][j]+1:
m+(A[i-1][j]+1)%m;
//3.对应第2组的对手也要做相应的安排
A[(A[i][j]-1)][j]=i+1;
}
}
return;
}
3、运行结果
当N为奇数时,结果截图:
当N为偶数时,结果截图:
4、源程序
#include
#include
int**A;//int*指针数组,
int*schedule;//int数组,一维数组保存二维数组的数据
intN=1;//问题的规模。
初始化时会设定
//isodd:
判断x是否奇数,是则返回1,否则0
intisodd(intx)
{
returnx&1;
}
//print:
打印赛程
voidprint()
{
inti,j,row,col;
if(isodd(N))
{
row=N;
col=N+1;
}
else
{
row=N;
col=N;
}
printf("第1列是选手编号\n");
for(i=0;i{
for(j=0;j
{
printf("%4d",A[i][j]);
}
printf("\n");
}
}
/*init:
初始化,设置问题规模N值,分配内存,用schedule指向;
把A构造成一个二维数组
*/
voidinit()
{inti,n;
charline[100]={'\0'};
printf("请输入选手人数:
");
fgets(line,sizeof(line),stdin);
N=atoi(line);
if(N<=0)exit(-1);
if(isodd(N))
n=N+1;
else
n=N;
//schedule是行化的二维数组
schedule=(int*)calloc(n*n,sizeof(int));
A=(int**)calloc(n,sizeof(int*));
if(!
schedule||A==NULL)exit(-2);
for(i=0;i{
A[i]=schedule+i*n;
A[i][0]=i+1;//初始化这个数组的第一列
}
return;
}
/*replaceVirtual:
把第m号虚的选手去掉(换做0)*/
voidreplaceVirtual(intm)
{
inti,j;
for(i=0;i对应选手号1~m-1
{
for(j=0;j<=m;j++)//列:
比行要多1
A[i][j]=(A[i][j]==m)?
0:
A[i][j];
}
return;
}
/*copyeven:
m为偶数时用,由前1组的m位选手的安排,来构成第2组m位选手
的赛程安排,以及两组之间的比赛安排*/
voidcopyeven(intm)
{
if(isodd(m))return;
inti,j;
for(j=0;j{
for(i=0;i{
A[i+m][j]=A[i][j]+m;
}
}
for(j=m;j<2*m;j++)//两组间比赛的安排
{
for(i=0;i{
A[i][j]=A[i+m][j-m];//把左下角拷贝到右上角
}
for(i=m;i<2*m;i++)//3.对应的,第2组和第1组
{
A[i][j]=A[i-m][j-m];//把左上角拷贝到右下角
}
}
return;
}
/*copyodd:
m为奇数时用,由前1组的m位选手的安排,来构成第2组m位选手
的赛程安排,以及两组之间的比赛安排。
这时和m为偶数时的
处理有区别。
*/
voidcopyodd(intm)
{
inti,j;
for(j=0;j<=m;j++)//1.求第2组的安排(前m天)
{
for(i=0;i{
if(A[i][j]!
=0)
{
A[i+m][j]=A[i][j]+m;
}
else//特殊处理:
两个队各有一名选手有空,安排他们比赛
{
A[i+m][j]=i+1;
A[i][j]=i+m+1;
}
}
}
//安排两组选手之间的比赛(后m-1天)
for(i=0,j=m+1;j<2*m;j++)
{
A[i][j]=j+1;//2.1号选手的后m-1天比赛
A[(A[i][j]-1)][j]=i+1;//3.他的对手后m-1天的安排
}
//以下的取值要依赖于1号选手的安排,所以之前先安排1号的赛程
for(i=1;i{
for(j=m+1;j<2*m;j++)
{//2.观察得到的规则一:
向下m+1~2*m循环递增
A[i][j]=((A[i-1][j]+1)%m==0)?
A[i-1][j]+1:
m+(A[i-1][j]+1)%m;
//3.对应第2组的对手也要做相应的安排
A[(A[i][j]-1)][j]=i+1;
}
}
return;
}
/*makecopy:
当前有m位(偶数)选手,分成两组,每组由m/2位选手构成
由第一组的m/2位选手的安排来构成第二组的比赛安排,第一
组与第二组的比赛安排。
要区分m/2为奇数和偶数两种情况
*/
voidmakecopy(intm)
{
if(isodd(m/2))//m/2为奇数
copyodd(m/2);
else//m/2为偶数
copyeven(m/2);
}
voidtournament(intm)
{
if(m==1)
{
A[0][0]=1;
return;
}
elseif(isodd(m))//如果m为奇数,则m+1是偶数
{
tournament(m+1);//按照偶数个选手来求解
replaceVirtual(m+1);//然后把第m+1号虚选手置成0
return;
}
else//m是偶数,
{
tournament(m/2);//则先安排第1组的m/2人比赛
makecopy(m);//然后根据算法,构造左下、右下、右上、右下的矩阵
}
return;
}
/*endprogram:
回收分配的内存*/
voidendprogram()
{
free(schedule);
free(A);
}
intmain()
{
init();//初始化
tournament(N);//求解
print();//打印结果
endprogram();//回收内存
return0;
}
实验二:
1、问题描述:
采用舍伍德(Sherwood)思想,完成快速排序。
写一算法实现。
2、算法描述:
在这里,用舍伍德型选择算法随机的选择一个数组元素作为划分标准。
这样既能保证算法的线性时间平均性能又避免了计算拟中位数的麻烦。
非递归的舍伍德型算法可描述如下:
template
Typeselect(Typea[],intl,intr,intk)
{//计算a[l:
r]中第K个元素
staticRandomNumberrnd;
while(true)
{
if(l>=r)
returna[l];
inti=l;
j=l+rnd.Random(r-l+1);//随机选择的划分基准
Swap(a[i],a[j]);
j=r+1;
Typepivot=a[l];
//以划分基准为轴作元素交换
while(true)
{
while(a[++i]while(a[--j]>pivot);
if(i>=j)break;
Swap(a[i],a[j]);
}
if(j-l+1==k)returnpivot;
a[l]=a[j];
a[j]=pivot;
//对子数组重复划分过程
if(j-l+1{
k=k-j+l-1;
l=j+1;
}
elser=j-1;
}
}
template
TypeSelect(Typea[],intn,intk)
{
//计算a[0:
n-1]中第K小元素
//假设a[n]是一个键值无穷大的元素
if(k<1||k>n)throwOutOfBounds();
returnselect(a,0,n-1,k);
}
3、实验结果
Number:
100000
Number:
10000
Number:
1000
Number:
100
Number:
10
Number:
1
4、源程序
random.h
#include
#include
usingnamespacestd;
//generaterandomnumbers
classrandomNumber
{
public:
randomNumber(longs=0);//initializetherandomnumbergenerator
longrandom();//returna32-bitrandomintegerm,1<=m<=2^31-2
//returna32-bitrandomintegerm,0<=m<=n-1,
//wheren<=2^31-1
longrandom(longn);
//returnarealnumberx,0<=x<1
doublefrandom();
private:
staticconstlongA;
staticconstlongM;
staticconstlongQ;
staticconstlongR;
longseed;
};
constlongrandomNumber:
:
A=48271;
constlongrandomNumber:
:
M=2147483647;
constlongrandomNumber:
:
Q=M/A;
constlongrandomNumber:
:
R=M%A;
randomNumber:
:
randomNumber(longs)
{
if(s<0)
s=0;
if(s==0)
{
//gettimeofdayinsecondssince12:
00AM,
//January1,1970
longt_time=time(NULL);
//mix-upbitsbysquaring
t_time*=t_time;
//resultcanoverflow.handlecases
//>0,<0,=0
if(t_time>0)
s=t_time^0x5EECE66DL;
elseif(t_time<0)
s=(t_time&0x7fffffff)^0x5EECE66DL;
else
s=0x5EECE66DL;
}
seed=s;
}
longrandomNumber:
:
random()
{
longtmpSeed=A*(seed%Q)-R*(seed/Q);
if(tmpSeed>=0)
seed=tmpSeed;
else
seed=tmpSeed+M;
returnseed;
}
longrandomNumber:
:
random(longn)
{
doublefraction=double(random())/double(M);
returnint(fraction*n);
}
doublerandomNumber:
:
frandom()
{
returndouble(random())/double(M);
}
timer.h
#ifndefTIMER_CLASS
#defineTIMER_CLASS
#include//declaresclock_ttype,functionclock(),
//andconstantCLOCKS_PER_SEC
classtimer
{
private:
//startingandendingtimemeasuredinclockticks
clock_tstartTime,endTime;
public:
timer();
//initializethetimer.
//Postconditions:
setthestartingandendingeventtimesto0.
//thiscreatesaneventwhosetimeis0.0
voidstart();
//starttiminganevent.
//Postcondition:
recordthecurrenttimeasthestartingtime
voidstop();
//stoptiminganevent.
//Postconditon:
recordthecurrenttimeastheendingtime
doubletime()const;
//returnthetimetheeventtookinsecondsbycomputing
//thedifferencebetweentheendingandstartingtimes.
};
//***********************************************************
//timerclassimplementation
//***********************************************************
//constructor.setstartingandendingtimesto0
timer:
:
timer():
startTime(0),endTime(0)
{}
//determineclockticksatstart
voidtimer:
:
start()
{
startTime=clock();
}
//determineclockticksatend
voidtimer:
:
stop()
{
endTime=clock();
}
//returntheelapsedtimeinseconds
doubletimer:
:
time()const
{
return(endTime-startTime)/double(CLOCKS_PER_SEC);
}
#endif//TIMER_CLASS
sherwood.cpp
#include
#include"random.h"
#include"timer.h"
#defineNUMBER100000//自定义排序数组的大小
template
voidQuickSort(Typea[],intp,intr)
{
if(p{
intq=Partition(a,p,r);
QuickSort(a,p,q-1);
QuickSort(a,q+1,r);
}
}
template
intRandomizedPartition(Typea[],intp,intr)
{
randomNumberrand;
//产生一个大于等于p小于等于r的值
inti=p+rand.random(r-p+1);
Typetemp;
//交换a[i]与a[j]的值
temp=a[i];
a[i]=a[p];
a[p]=temp;
returnPartition(a,p,r);
}
template
intPartition(Typea[],intp,intr)
{
inti=p,j=r+1;
Typetemp;
Typex=a[p];
//将小于x的元素交换到左边区域,大于x的元素交换到右边区域
while(true)
{
while(a[++i]while(a[--j]>x);
if(i>=j)break;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
a[p]=a[j];
a[j]=x;
returnj;
}
template
voidRandomizedQuickSort(Typea[],intp,intr)
{
if(p{
intq
|