随机算法比较.docx
《随机算法比较.docx》由会员分享,可在线阅读,更多相关《随机算法比较.docx(14页珍藏版)》请在冰豆网上搜索。
![随机算法比较.docx](https://file1.bdocx.com/fileroot1/2022-11/28/93192254-adb2-4cdd-a795-8d89f07a497f/93192254-adb2-4cdd-a795-8d89f07a497f1.gif)
随机算法比较
一、问题描述:
分别用KMP、MonteCarlo和LasVegas算法编制3个程序,并随机生成不小于5000对、长度很长、且长度不等的01串X和Y(三个程序处理相同的串),然后统计算法的执行时间、MonteCarlo算法的出错率,并根据运行结果对三种算法进行深入的比较(长度可试50、500、5000、50000位,Y不能太短)。
注意,先利用附件所给素数随机取若干实现上述算法,学完素数判定算法之后将该算法编程,产生一定数量的随机素数(长度比Y串至少少4位且数值不超过200万),并把这些素数用数组保存起来,执行子串匹配随机算法时,每次随机从中取一个素数后再运行子串匹配随机算法,三个程序都要记录对给定字符串的算法运行时间。
(对随机取素数和子串匹配随机算法分别计算时间)
二、算法设计和分析:
KMP算法
KMP算法的主要特点是指向主串的指针不需要回溯,只向右移动,即模式串在与主串失配时,并不回溯主串的指针与模式串重新匹配,而是根据已经得到的匹配信息将模式串尽可能远的向右滑动一段。
滑动距离的大小取决于模式串的失效函数next,next[k](0<=k<=m-1)的值表示当模式串在下标为k的字符处与主串失配时应该向右移动到下标为next[k]的字符处再与主串重新匹配。
算法首先要求模式串的失效函数next,然后再根据next的值进行模式匹配,在最坏情况下的时间复杂度为O(m*n),m为模式串的长度,n为主串的长度,当如果模式串中有较多相同的字符时,时间复杂度一般可达到O(m+n)。
程序流程图如下:
MonteCarlo算法
MonteCarlo随机算法主要是通过比较模式串和主串中与模式串等长的串的“指纹”来匹配的,若两者指纹相等,则可以认为在概率意义下两者是相等的,算法中要求用到一个随机产生的素数作模运算,该素数的选取直接影响了算法的准确率,算法的时间复杂度为O(m+n)。
但有一定的出错率,即选取主串中比较串的指纹与模式串相等时但比较串与模式串并不相等,理论上这种情况出现的概率为1/n,只与主串的长度有关,与模式串的长度无关,但实际上只要选取素数合适出错率比1/n要小的多。
程序流程图如下:
LasVegas算法
LasVegas算法是对MonteCarlo算法的改进,当模式串的指纹与主串中的比较串相等时,此时并不直接返回匹配的位置,而是判断两个字符串是否真的相等,相等则返回,否则继续匹配。
所以,该算法总能得到正确的位置,但算法的执行时间稍微比MonteCarlo算法要长一点(判断字符串是否相等的耗费),时间复杂度的期望值不超过O(m+n)。
程序流程图如下:
三、程序运行结果:
四、程序源码:
#include
#include
#include
#include
usingnamespacestd;
constintCOUNT=100000;//数的对数
constintMAXLEN=500;
intx[COUNT];
inty[COUNT];
intlenx[COUNT];
intleny[COUNT];
//素数的生成
intget_prime(intnum)
{
intm=(num*num)*2;
if(m<=250)
{
return211;
}
elseif(m<=500)
{
return461;
}
elseif(m<=1000)
{
return953;
}
elseif(m<=5000)
{
return1957;
}
elseif(m<=10000)
{
return9233;
}
else
{
return100003;
}
}
//获取已知长度的随机数
intgetrandom_num(intlen)
{
inttemp=0;
while(len>16)
{
temp=temp<<16;
len=len-16;
temp+=rand();
}
temp=temp<temp=temp+rand()%(1<returntemp;
}
//获取一个二进制数串的第n位
intget_n_bit(intnum,intn,intlen)
{
num=num>>(len-n);
num=(num%2);
returnnum;
}
//初始化数据
voidinit()
{
srand((int)time(NULL));
for(inti=0;i{
lenx[i]=rand()%MAXLEN;//随机一个2进制长度
leny[i]=rand()%MAXLEN;
x[i]=getrandom_num(lenx[i]);//随机该长度的数
y[i]=getrandom_num(leny[i]);
}
}
//获取i[x]mopp后的值get_len为获取的长度,all_len为总长,pos是开始的位置prime_num是素数
intget_ip(intnum,intget_len,intall_len,intpos,intprime_num)
{
num=num>>(all_len-get_len+1-pos);
inta=1<--a;//获得get_len长全为1的串
num=num&a;
num=num%prime_num;
returnnum;
}
//获取子串
intget_string(intnum,intall_len,intget_len,intpos)
{
num=num>>(all_len-get_len+1-pos);
inta=1<--a;
num=num&a;
returnnum;
}
//KMP
voidgetNext(intnext[],inty,intlen)
{
intj,k;
next[0]=-1;
j=0;
k=-1;
while(j{
if(k==-1||get_n_bit(y,j+1,len)==get_n_bit(y,k+1,len))//匹配的情况下,p[j]==p[k]
{
j++;
k++;
next[j]=k;
}
else//p[j]!
=p[k]
k=next[k];
}
}
boolKMP(intx,inty,intlenx,intleny)
{
if(leny==0)
returntrue;
intnext[64];
inti,j;
i=0;
j=0;
getNext(next,y,leny);
while(i{
if(j==-1||get_n_bit(x,i+1,lenx)==get_n_bit(y,j+1,leny))
{
i++;
j++;
}
else
{
j=next[j];
}
if(j==leny)
returntrue;
}
returnfalse;
}
//MonteCarlo算法
boolmontecarlo(intx,inty,intlx,intly)
{
if(leny==0)
{
returntrue;
}
intp=get_prime(lx);//取随机数;
intj=1;
intipx=get_ip(x,ly,lx,1,p);//算Ip[x]Ip[y]
intipy=get_ip(y,ly,ly,1,p);
while(j<=lx-ly+1)
{
if(ipx==ipy)
{
returntrue;
}
else//算Ip[x+1]
{
ipx=((ipx<<1)-((1<ipx=ipx<0?
ipx+p:
ipx;
ipx=ipx>p?
ipx-p:
ipx;
}
++j;
}
returnfalse;
}
//LASVegas算法(找y是x的子串)
boollasvegas(intx,inty,intlx,intly)
{
if(leny==0)
{
returntrue;
}
intp=get_prime(lx);//取随机数;
intj=1;
intipx=get_ip(x,ly,lx,1,p);//算Ip[x]Ip[y]
intipy=get_ip(y,ly,ly,1,p);
while(j<=lx-ly+1)
{
if(ipx==ipy)
{
if(get_string(x,lx,ly,j)==y)
{
returntrue;
}
}
else//算Ip[x+1]
{
ipx=((ipx<<1)-((1<ipx=ipx<0?
ipx+p:
ipx;
ipx=ipx>p?
ipx-p:
ipx;
}
++j;
}
returnfalse;
}
voidmain()
{
init();
intCount1=0;
intCount2=0;
intCount3=0;
intsum=0;
struct_timebtstruct1;//时间格式
struct_timebtstruct2;
inttime;
inti;
cout<<"长度为"<"<//KMP
_ftime(&tstruct1);//start
for(i=0;i{
if(lenx[i]>=leny[i])
{
/*montecarlo*/
if(KMP(x[i],y[i],lenx[i],leny[i]))
Count3++;
}
}
_ftime(&tstruct2);//end
cout<<"***************************************"<cout<<"KMP算法"<cout<<"子串的数:
"<time=(tstruct2.time*1000+tstruct2.millitm)-(tstruct1.time*1000+tstruct1.millitm);
cout<<"使用时间:
"<