状态机资料.docx
- 文档编号:29571810
- 上传时间:2023-07-24
- 格式:DOCX
- 页数:44
- 大小:98.04KB
状态机资料.docx
《状态机资料.docx》由会员分享,可在线阅读,更多相关《状态机资料.docx(44页珍藏版)》请在冰豆网上搜索。
状态机资料
//strstr.c
#include
#include
main()
{
char*s="GoldenGlobalView";
char*l="lob";
char*p;
clrscr();
p=strstr(s,l);
if(p)
printf("%s",p);
else
printf("NotFound!
");
getchar();
return0;
}
语法:
*strstr(str1,str2)
str1:
被查找目标 stringexpressiontosearch.
str2:
要查找对象 Thestringexpressiontofind.
该函数返回str2第一次在str1中的位置,如果没有找到,返回NULL
Thestrstr()functionreturnstheordinalpositionwithinstr1ofthefirstoccurrenceofstr2.Ifstr2isnotfoundinstr1,strstr()returns0.
例子:
功能:
从字串”string1onexxxstring2oneyyy”中寻找”yyy”
(假设xxx和yyy都是一个未知的字串)
char*s=”string1onexxxstring2oneyyy”;
char*p;
p=strstr(s,”string2”);
if(p==NULL)printf(“NotFound!
”);
p=strstr(p,”one”);
if(p==NULL)printf(“NotFound!
”);
p+=strlen(“one”);
printf(“%s”,p);
说明:
如果直接写语句p=strstr(s,”one”),则找到的是onexxxstring2oneyyy,不符合要求
所以需采用二次查找法找到目标
实现
char*mystrstr(char*s1,char*s2)
{
if(*s1==0)
{
if(*s2)return(char*)NULL;
return(char*)s1;
}
while(*s1)
{
inti=0;
while
(1)
{
if(s2[i]==0)returns1;
if(s2[i]!
=s1[i])break;
i++;
}
s1++;
}
return(char*)NULL;
}
intmain()
{
charstr[]="rocrocketisme.";
charsubstr[]="ti";
intstrsize;
intsubsize;
subsize=strlen(substr);
strsize=strlen(str);
inti=0,j=0;
while((j!
=subsize)&&(i!
=strsize)){
if(str[i]==substr[j]){
i++;
j++;
}else{
i=i-j+1;
j=0;
}
}
if(j==subsize){
printf("Matched!
\n");
}else{
printf("Pity!
\n");
}
return0;
}
strstr()的实现
strstr(s1,s2)是一个经常用的函数,他的作用就是在字符串s1中寻找字符串s2如果找到了就返回指针,否则返回NULL。
char*strstr(constchar*s1,constchar*s2)
{
unsignedinti=0;
if(*s1==0)//如果字符串s1为空
{
if(*s2)//如果字符串s2不为空
return(char*)NULL;//则返回NULL
return(char*)s1;//如果s2也为空,则返回s1
}
while(*s1)//串s1没有结束
{
i=0;
while
(1)
{
if(s2[i]==0)
{
return(char*)s1;
}
if(s2[i]!
=s1[i])
break;
i++;
}
s1++;
}
return(char*)NULL;
}
/*
*strstr.c--returntheoffsetofonestringwithinanother.
*
*Copyright(C)1997FreeSoftwareFoundation,Inc.
*
*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyitunder
*thetermsoftheGNUGeneralPublicLicenseaspublishedbytheFree
*SoftwareFoundation;eitherversion2,or(atyouroption)anylater
*version.
*
*Thisprogramisdistributedinthehopethatitwillbeuseful,butWITHOUT
*ANYWARRANTY;withouteventheimpliedwarrantyofMERCHANTABILITYor
*FITNESSFORAPARTICULARPURPOSE.SeetheGNUGeneralPublicLicensefor
*moredetails.
*
*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicensealongwith
*thisprogram;ifnot,writetotheFreeSoftwareFoundation,Inc.,59
*TemplePlace-Suite330,Boston,MA02111-1307,USA.
*/
/*WrittenbyPhilippeDeMuyter
/*
*NAME
*
*strstr--locatefirstoccurrenceofasubstring
*
*SYNOPSIS
*
*char*strstr(char*s1,char*s2)
*
*DESCRIPTION
*
*LocatesthefirstoccurrenceinthestringpointedtobyS1ofthestring
*pointedtobyS2.Returnsapointertothesubstringfound,oraNULL
*pointerifnotfound.IfS2pointstoastringwithzerolength,the
*functionreturnsS1.
*
*BUGS
*
*/
char*
strstr(buf,sub)
registerchar*buf;
registerchar*sub;
{
registerchar*bp;
registerchar*sp;
if(!
*sub)
returnbuf;
while(*buf)
{
bp=buf;
sp=sub;
do{
if(!
*sp)
returnbuf;
}while(*bp++==*sp++);
buf+=1;
}
return0;
一定义
1主串S=s1s2…sn,即由n个字符组成的字符串
2模式串T=t1t2…tm,即由m个字符组成的字符串
3字符串匹配问题定义:
给定主串S与模式串T,若S中含有T,返回T第一次出现的位置,否则返回-1.
二普通做法
for(inti=0;i for(intj=0;j if(j==m)returni; } return-1; 三有限状态自动机 有限状态自动机可以用5元式定义,即输入字符集,状态集,初始状态集,接受状态集,状态转移函数. 我们常用的正则表达式其实就是有限状态自动机,能够用有限状态自动机表示的语言即为正则语言. 字符串匹配本质也是一个模拟有限状态自动机的过程,即构造一个FA,该FA只接受所有含有字符串T的字符串.若输入串S被该FA接受,则表明S含有T. 假设T=”ababcab” 其上述普通做法所模拟的FA可以描述如下: 每次内层循环开始,状态为0,若下一个字符串为a,则状态转为1,也即j++,直到j=7,即识别了字符串”ababcab”,到达了接受状态7.相反,假设在状态2时,下一个输入字符不是’a’,则匹配失败,此时应该重新回归起始状态,在代码中的具体体现就是退出内层循环,i++,再进入内层循环,此时j=0,即重新从状态0开始。 但是上述FA不是通常意义上的FA,其效率非常低,有两个原因: 1)每次匹配失败,状态重新回归0,即j=0。 2)每次匹配失败,回退1…j个字符,即i=i+1,本来已经读取到了i+j。 上述两个回退分别体现在内循环与外循环,,比如我们在j=2时发现匹配失败,此时已经读取了i+2个字符,但是退出内层循环,只是i++,再重复读取字符,即从i+1开始重复读取字符,而第i+1,i+2个字符已经被读取了,按道理不应该重复计算。 并且状态2应该具有对历史匹配的记忆能力,即状态2表示了0->1->2的过程,表示“ab”已经匹配了。 如何利用这些已知匹配信息来提高计算速度呢? 主要从两点入手: 1)每次匹配失败,状态回归到最近一个等价状态,比如状态3的等价状态应该是1,因为1表示已匹配字符‘a’,而3表示已匹配‘aba’,当然不能说1与3完全等价,只有在接下来的输入不是b时,状态3可看作与1等价因为,此时表示”aba”匹配没有意义,最多只有最后1个“a”还有意义,因为0->1也是表示匹配“a”,所以可以看作3与1等价。 2)主串不需要回退,即不再需要外层循环。 首先我们可以假设任意一个状态具有两个跳转函数,其中1个若读取匹配的字符,跳转到下一个状态即i++,j++,另外一个即空跳转(读取ε)到初始状态0,当然空跳转只是在不匹配的情况下才使用,即j=0,注意由于是空跳转,即表示不读取任何输入,此时i不变,这也是合理的,因为si! =tj,那么留着si用于接下来的匹配。 根据以上分析,我们可以得出下属FA: 分析: 1)状态0时,若输入不是a,则0->0;这里不是空跳转,注意若在起始状态如果不断空跳转,那么程序中的表现即i不变,陷入死循环。 2)对于任意状态k,若不匹配,则需要回退到前面的状态,在前面我们都是让其回归初始状态,为了提高效率,让其回归最近一个“等价”状态,那么如何计算最近1个等价状态呢? 定义“等价”状态函数next[k],设想我们先找k的前状态k-1的等价状态next[k-1],若t[next[k-1]]=t[k-1],即表示next[k-1]->next[k-1]+1与k-1->k的跳转条件相同,那么可定义next[k]=next[k-1]+1,形象来说,即k-1的等价状态next[k-1]表示0,…,next[k-1]-1个字符与k-next[k-1],…,k-1个字符相同,那么如果第next[k-1]个字符与k-1个字符相同,相当于0,…,next[k-1]=k-next[k-1],…,k即表示next[k]=next[k-1]+1,但是这是一个递推的过程,即如果t[next[k-1]]=t[k-1],那么判断是否t[next[next[k-1]]]=t[k-1] 在此可以定义next函数为: 若k=0,则next[k]=-1/*设其为-1,一方面可以在下述递推中作为终止条件,另外也可以在0状态时,避免空跳转*/ 若k>0,且t[k-1]=t[next[k-1]],则next[k]=next[k-1]+1,否则递推判断是否t[k-1]=t[next[next[k-1]]],…;否则next[k]=0 具体程序Java实现如下: intindex(charsrc[],charpattern[]) { int[]next=getNext(pattern); inti=0,j=0; while(i if(j==-1){//起始位置不匹配,继续往前读 i++; j=0; } elseif(pattern[j]==src[i]){//状态转移 i++; j++; } elsej=next[j];//只改变状态j,i不变,即空跳转 } if(j==pattern.length)returni-j; elsereturn-1; } int[]getNext(charpattern[]) { int[]next=newint[pattern.length]; next[0]=-1; for(inti=1;i next[i]=0;//初始化为0 intj=i-1; while(next[j]>=0){//递推求解next,-1为终止条件,即j=0时 if(pattern[i-1]==pattern[next[j]]){ next[i]=next[j]+1; break; } elsej=next[j]; } } returnnext; } 需要确认注册邮箱后才能下载,立即确认我的邮箱 有限状态机FSM思想广泛应用于硬件控制电路设计,也是软件上常用的一种处理方法(软件上称为FMM--有限消息机)。 它把 复杂的控制逻辑分解成有限个稳定状态,在每个状态上判断事件,变连续处理为离散数字处理,符合计算机的工作特点。 同 时,因为有限状态机具有有限个状态,所以可以在实际的工程上实现。 但这并不意味着其只能进行有限次的处理,相反,有限 状态机是闭环系统,有限无穷,可以用有限的状态,处理无穷的事务。 有限状态机的工作原理如图1所示,发生事件(event)后,根据当前状态(cur_state),决定执行的动作(action),并设置 下一个状态号(nxt_state)。 ------------- | |-------->执行动作action 发生事件event----->|cur_state| | |-------->设置下一状态号nxt_state ------------- 当前状态 图1有限状态机工作原理 e0/a0 --->-- | | -------->---------- e0/a0| | S0 |----- | -<------------ |e1/a1 | |e2/a2 V ---------- ---------- | S2 |-----<-----| S1 | ---------- e2/a2 ---------- 图2一个有限状态机实例 -------------------------------------------- 当前状态 s0 s1 s2 |事件 -------------------------------------------- a0/s0 -- a0/s0 | e0 -------------------------------------------- a1/s1 -- -- | e1 -------------------------------------------- a2/s2 a2/s2 -- | e2 -------------------------------------------- 表1图2状态机实例的二维表格表示(动作/下一状态) 图2为一个状态机实例的状态转移图,它的含义是: 在s0状态,如果发生e0事件,那么就执行a0动作,并保持状态不变; 如果发生e1事件,那么就执行a1动作,并将状态转移到s1态; 如果发生e2事件,那么就执行a2动作,并将状态转移到s2态; 在s1状态,如果发生e2事件,那么就执行a2动作,并将状态转移到s2态; 在s2状态,如果发生e0事件,那么就执行a0动作,并将状态转移到s0态; 有限状态机不仅能够用状态转移图表示,还可以用二维的表格代表。 一般将当前状态号写在横行上,将事件写在纵列上, 如表1所示。 其中“--”表示空(不执行动作,也不进行状态转移),“an/sn”表示执行动作an,同时将下一状态设置为sn。 表1和 图2表示的含义是完全相同的。 观察表1可知,状态机可以用两种方法实现: 竖着写(在状态中判断事件)和横着写(在事件中判断状态)。 这两种实现在本 质上是完全等效的,但在实际操作中,效果却截然不同。 ================================== 竖着写(在状态中判断事件)C代码片段 ================================== cur_state=nxt_state; switch(cur_state){ //在当前状态中判断事件 cases0: //在s0状态 if(e0_event){ //如果发生e0事件,那么就执行a0动作,并保持状态不变; 执行a0动作; //nxt_state=s0; //因为状态号是自身,所以可以删除此句,以提高运行速度。 } elseif(e1_event){ //如果发生e1事件,那么就执行a1动作,并将状态转移到s1态; 执行a1动作; nxt_state=s1; } elseif(e2_event){ //如果发生e2事件,那么就执行a2动作,并将状态转移到s2态; 执行a2动作; nxt_state=s2; } break; cases1: //在s1状态 if(e2_event){ //如果发生e2事件,那么就执行a2动作,并将状态转移到s2态; 执行a2动作; nxt_state=s2; } break; cases2: //在s2状态 if(e0_event){ //如果发生e0事件,那么就执行a0动作,并将状态转移到s0态; 执行a0动作; nxt_state=s0; } } ================================== 横着写(在事件中判断状态)C代码片段 ===============================
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 状态机 资料