算法设计B10040101.docx
《算法设计B10040101.docx》由会员分享,可在线阅读,更多相关《算法设计B10040101.docx(21页珍藏版)》请在冰豆网上搜索。
![算法设计B10040101.docx](https://file1.bdocx.com/fileroot1/2022-11/22/ebe27f37-741f-4bb8-9e7b-bdd8ff5a7cf1/ebe27f37-741f-4bb8-9e7b-bdd8ff5a7cf11.gif)
算法设计B10040101
算法与数据结构设计报告
(2011/2012学年第二学期)
题目:
模式匹配算法的设计与实现
专业计算机科学与技术
学生姓名王欣源
班级学号B10040101
指导教师肖甫
指导单位计算机科学与技术系
日期2012年6月1日
评分细则
评分项
优秀
良好
中等
差
遵守机房规章制度
上机时的表现
学习态度
程序准备情况
程序设计能力
团队合作精神
课题功能实现情况
算法设计合理性
用户界面设计
报告书写认真程度
内容详实程度
文字表达熟练程度
回答问题准确度
简短评语
教师签名:
年月日
评分等级
备注
评分等级有五种:
优秀、良好、中等、及格、不及格
一.课题名称:
模式匹配算法的设计与实现
设计要求:
理解模式匹配的含义,掌握简单匹配算法及模式匹配KMP算法的思想,实现以下任务:
(1)编程动态实现简单模式匹配算法及模式匹配KMP算法;
(2)根据给定的主串与模式串,给出根据两种匹配算法进行匹配的各趟匹配结果;
(3)测试用例:
主串:
ThrougharetrospectivelookatthemathematicsteachingatUSTC,thisarticlesummarizesuniversity’steachingachievementsinpast45years.
匹配子串:
teaching
输出结果:
匹配子串teaching出现在主串中的次数为2
2次的匹配的位置分别是:
48104;
(4)一个应用实例如下:
●要求编写建立一个文本文件,每个单词不包括空格且不跨行,单词由字符序列构成,且区分大小写;
●统计给定单词在文本中出现的总次数;
检索出某个单词在文本中的行号、在该行中出现的次数及位置。
二.课题内容和要求
本题主要是要掌握模式匹配的含义,以及KMP模式匹配算法相比简单模式匹配算法优越性。
模式匹配是指有两个串S和P,在串S中找P的过程。
其中S是主串,P是模式串。
简单匹配算法是从主串S中下标i的字符与模式串P的第1个字符开始逐个比较,遇到不相等时,即达到失配点,该趟匹配失败,S回到原来的i+1的位置,P回到第1个字符位置,继续下一趟匹配,直到匹配成功。
简单模式匹配算法效率不高,原因在于匹配过程中有回溯。
而KMP算法中,i只进不退,对串S来说就消除了回退。
本课题要求用简单模式匹配和KMP模式匹配分别来测试用例:
ThrougharetrospectivelookatthemathematicsteachingatUSTC,thisarticlesummarizesuniversity’steachingachievementsinpast45years.其中模式串是:
teaching,经过测试后都应该得到的结果是:
匹配子串teaching出现在主串中的次数为2,2次的匹配的位置分别是:
46102;如果加入一个能计算时间的函数后,应该得到的结果是用简单模式匹配的时间比KMP模式匹配运行的时间长。
由此,就可以得到在测试样例较多的情况下选用算法会节省时间,这对一些项目来说是很重要的,就突出了KMP算法的优越性。
在课题要求中的应用实例中,要求1.建立一个文本文件,要求编写建立一个文本文件,每个单词不包括空格且不跨行,单词由字符序列构成,且区分大小写;2.编写程序能够读入文本文件中的内容,运用已经写好的程序统计给定单词在文本中出现的总次数;3.能够检索出某个单词在文本中的行号、在该行中出现的次数及位置。
KMP算法也有优化的地方。
在此,我又将改进的KMP算法也写进去了,三种方法可以放在一起比较,找出最优化的算法。
三.需求分析
1.实现简单模式匹配的函数,其中公有函数Find(String&p)调用私有函数Find(int
i,String&p),私有函数每次在主串中找出一个模式串,而公有函数可以计算出所有的模式串的个数和位置。
intString:
:
Find(inti,String&P)//代码具体见详细设计
intString:
:
Find(String&P)//代码具体见详细设计
2.实现KMP模式匹配的函数,其中公有函数KMPFind(String&p)调用私有函数KMPFind(inti,String&p),私有函数每次在主串中找出一个模式串,而公有函数可以计算出所有的模式串的个数和位置。
intString:
:
KMPFind(inti,String&P)//代码具体见详细设计
intString:
:
KMPFind(String&P)//代码具体见详细设计
3.实现改进的KMP模式匹配的函数,其中公有函数KMPFindImprove(String&p)调用私有函数KMPFindImprove(inti,String&p),私有函数每次在主串中找出一个模式串,而公有函数可以计算出所有的模式串的个数和位置。
intString:
:
KMPFindImprove(inti,String&P)//代码具体见详细设计
intString:
:
KMPFindImprove(String&P)//代码具体见详细设计
4.经过比较后改进的KMP算法是最优化的,所以在读取文件、测试文件时采用该进的KMP算法来做。
其中取文件的函数Read()要自己设计
voidString:
:
Read(char*file)//代码具体见详细设计
5.main()函数中做了一个菜单,可以根据不同的选择测试不同的功能。
四.设计概要
1.程序的算法设计说明,采用流程图形式
2.每个程序中使用的存储结构设计说明
因为采用的是面向对象C++的方法,定义了一个String类,其String类中成员变量和成员函数原型声明如下:
classString
{
Private:
intn;
char*str;
int*count;//记录子串在主串中出现的位置
intFind(inti,String&P);//简单匹配算法找到最近的匹配串后立即停止,而不向下继续且缺乏一个数组记录位置
intfail();//记录失败函数
voidFail();
intKMPFind(inti,String&P);
voidImproveFail();//改进的失败函数
intKMPFindImprove(inti,String&P);
public:
String();//建立一个空串
String(constchar*p);
String(constString&p);//拷贝函数
~String();
intLength(){returnn;};//返回当前串对象长度
voidOutput(){cout<intFind(String&P);//简单匹配算法
intKMPFind(String&P);//KMP匹配算法
intKMPFindImprove(String&P);//改进的KMP匹配算法
voidOutput2();//输出子串在主串中出现的位置
voidOutput3();//输出子串所在行数,位置及总个数
voidRead(char*);
};
各个功能段均采用数组的存储结构。
五.详细设计
#include
#include
#include
#include
#include
usingnamespacestd;
#defineMAX100000
#defineM69
classString
{
private:
intn;
char*str;
int*count;//记录子串在主串中出现的位置
intFind(inti,String&P);//简单匹配算法找到最近的匹配串后立即停止,而不向下继续且缺乏一个数组记录位置
int*f();//记录失败函数
voidFail();
intKMPFind(inti,String&P);//改进的失败函数
voidImproveFail();
intKMPFindImprove(inti,String&P);
public:
String();//建立一个空串
String(constchar*p);
String(constString&p);//拷贝函数
~String();
intLength(){returnn;};//返回当前串对象长度
voidOutput(){cout<intFind(String&P);//简单匹配算法
intKMPFind(String&P);//KMP匹配算法
intKMPFindImprove(String&P);//改进的KMP匹配算法
voidOutput2();//输出子串在主串中出现的位置
voidOutput3();//输出子串所在行数,位置及总个数
voidRead(char*);
};
String:
:
String()//无参数的构造函数进行初始化
{
n=0;
str=NULL;
count=NULL;
f=NULL;
}
String:
:
String(constchar*p)//有参数的构造函数
{
n=strlen(p);
str=newchar[n+1];
strcpy(str,p);
count=newint[n];
for(inti=0;icount[i]=0;
f=newint[n];
for(intj=0;jf[j]=-1;
}
String:
:
String(constString&p)//拷贝构造函数
{
n=p.n;
str=newchar[n+1];
if(str==NULL)exit
(1);
for(inti=0;istr[i]=p.str[i];
str[n]='\0';//结束标识符'\0',否则会出现乱码
count=newint[n];
for(intj=0;jcount[j]=p.count[j];
f=newint[n];
for(intk=0;kf[k]=p.count[k];
}
String:
:
~String()
{
delete[]str;
}
intString:
:
Find(inti,String&P)//简单匹配算法i为主串P的位置,开始置0
{
if(i<0||i>n-1)//越界检查
{
cout<<"Outofbounds!
"<return-1;
}
char*pp=P.str;//模式串指针pp指向第一个字符
char*t=str+i;//主串指针t指向下标i的字符
while(*pp!
='\x0'&&i<=n-P.n)//子串pp未到串尾且剩余字符超过模式串长,则循环
{
if(*pp++!
=*t++)
{
pp=P.str;//模式串回到第一个字符
t=str+(++i);//主串回到i+1的位置
}
}
if(*pp=='\0')
returni;//若pp已到串尾,则匹配成功
return-1;
}
intString:
:
Find(String&P)
{
intsum=0;
intj=Find(0,P);//共有find函数调用私有函数find
while(j!
=-1)
{
count[sum]=j;sum++;//count记录位置,sum记录次数
if(j<=n-P.n)
j=Find(j+P.n,P);
}
returnsum;
}
voidString:
:
Fail()//失败函数
{
intj=0,k=-1;
f[0]=-1;
while(j{
if((k==-1)||(str[j]==str[k]))
{
j++;k++;//k==-1或str[j]==str[k]时,j,k各扩展1位,j无回溯
f[j]=k;//求得的k存入f[j]
}
elsek=f[k];//str[j]不等于str[k]时,k回溯到f[k]
}
}
intString:
:
KMPFind(inti,String&P)
{
if(i<0||i>n-1)//越界检查
{
cout<<"Outofbounds!
"<return-1;
}
this->Fail();
intj=0,m=P.n;
while(i{
if(j==-1||str[i]==P.str[j])//相等或j=-1时,i、j均后移1个位置
{
i++;
j++;
}
else
j=P.f[j];//到达失配点,j回溯到f[j]
}
return((j==m)?
i-m:
-1);
}
intString:
:
KMPFind(String&P)
{
intsum=0;
intj=KMPFind(0,P);
while(j!
=-1)
{
count[sum]=j;sum++;//count记录位置,sum记录次数
if(j<=n-P.n)
j=KMPFind(j+P.n,P);
}
returnsum;
}
voidString:
:
ImproveFail()//改进的失败函数
{
intj=0,k=-1;
f[0]=-1;
while(j{
if((k==-1)||(str[j]==str[k]))//当k=-1或str[j]=str[k]时,j,k各扩展1位
{
j++;
k++;
if(str[j]==str[k])//将字符pk与pj比较,若相等则将f[k]存入f[j]
f[j]=f[k];
else
f[j]=k;//否则将k存入f[j]
}
else
k=f[k];//str[j]不等于str[k]时,k回溯到f[k],j无回溯
}
}
intString:
:
KMPFindImprove(inti,String&P)
{
if(i<0||i>n-1)
{
cout<<"Outofbounds!
"<return-1;
}
this->ImproveFail();
intj=0,m=P.n;
while(i{
if(j==-1||str[i]==P.str[j])
{
i++;
j++;
}
else
j=P.f[j];
}
return((j==m)?
i-m:
-1);
}
intString:
:
KMPFindImprove(String&P)
{
intsum=0;
intj=KMPFindImprove(0,P);
while(j!
=-1)
{
count[sum++]=j;
if(j<=n-P.n)j=KMPFindImprove(j+P.n,P);
}
returnsum;
}
voidString:
:
Read(char*file)//通过文件读取
{
charch;
char*temp=newchar[MAX];
inti=0;
ifstreaminfile(file);
if(!
file)//判断能否打开
{
cout<<"Cannotopenthefile!
"<return;
}
while(infile.get(ch)!
="#")
{
temp[i++]=ch;
if(ch=='#')//以#为结束标志
break;
}
temp[i]='\0';
n=i;
str=newchar[n];//由于定义一个空子串时n=0,count,f等都为NULL,所以此处要重新定义
for(intz=0;zstr[z]=temp[z];
count=newint[n];
for(intk=0;kcount[k]=0;
f=newint[n];
for(intj=0;jf[j]=-1;
infile.close();
delete[]temp;
}
voidString:
:
Output2()//输出子串在主串中的位置
{
inti=0;
while(count[i]!
=count[i+1]&&i{
cout<i++;
}
}
voidString:
:
Output3()//输出子串在文件中的行数、位置、及次数
{
inti=0;intt=0;
int*line=newint[MAX];//记录字符串在该行出现的次数
int*ram=newint[M];//记录字符串在该行出现的位置
for(intm=1;m<=MAX;m++)
line[m]=0;
for(intn=1;n<=M;n++)
ram[n]=0;
while(count[i]!
=count[i+1]&&i{
intl1=count[i]/M+1;
intl2=count[i+1]/M+1;//记录相邻两个字符串行数(要考虑到只有一行的情况)
intr=count[i]%M;//记录该字符串位置
line[l1]++;ram[t++]=r;
if((l1!
=l2&&count[i+1]>0)||(l1==l2&&count[i+1]==0))//换行
{
cout<<"该单词在第"<";
for(ints=0;scout<cout<t=0;
}
i++;//到下一行找
}
}
voidmain()
{
intchoise=0;
cout<<"******************************************************";cout<cout<<"******************************************************";cout<cout<<"##1.简单模式匹配做测试样例##";cout<cout<<"##2.KMP模式匹配做测试样例##";cout<cout<<"##3.改进的KMP模式匹配做测试样例##";cout<cout<<"##4.从文本测试函数##";cout<cout<<"##5.返回##";cout<cout<<"******************************************************";cout<cout<<"******************************************************";cout<while(choise!
=5){
cin>>choise;
if(choise==1){//简单模式匹配算法测试
clock_tstart,finish;
start=clock();
Strings1("ThrougharetrospectivelookatthemathematicsteachingatUSTC,thisarticlesummarizesuniversity’steachingachievementsinpast45years.");
s1.Output();cout<Strings2("teaching");
intm=s1.Find(s2);
cout<<"用简单模式匹配测匹配子串";
s2.Output();
cout<<"出现在主串中的次数为:
"<if(m!
=0)
{
cout<";
s1.Output2();
cout<}
finish=clock();
cout<"<<(double)(finish-start)/CLK_TCK<}
if(choise==2)//KMP模式匹配算法测试
{
clock_tstart,finish;
start=clock();
Strings1("ThrougharetrospectivelookatthemathematicsteachingatUSTC,thisarticlesummarizesuniversity’steachingachievementsinpast45years.");
s1.Output();cout<Strings2("teaching");
cout<<"用kmp模式匹配测匹配子串:
";
s2.Output();cout<intn=s1.KMPFind(s2);
cout<<"出现在主串中的次数为:
"<if(n!
=0)
{
cout<";
s1.Output2();
cout<}
finish=clock();
cout<"<<(double)(finish-start)/CLK_TCK<}
if(choise==3)//改进的KMP模式匹配算法测试
{
clock_tstart,finish;
start=clock