32.3-5帶有萬用字元的匹配(自動機)
阿新 • • 發佈:2019-02-11
功能
這個程式可以判斷一個帶有萬用字元*的模式串是否在文字串中存在,沒有記錄位置資訊,當然,想記錄也是可以的
樣例輸入:
abccbacbababc
ab*bab*c
樣例輸出:
1
思路
對於樣例輸入,有限自動機如圖所示:
我們把每個萬用字元隔開的字串看做獨立的,在其上執行KMP演算法的comput_suffix_function過程,區別僅在於每部分的開頭的fail指向上部分的結尾,每個部分的結尾fail指向自己(如果後面緊跟的一位匹配失敗,由於萬用字元可以代替任意長度的任意字串,不需要像KMP演算法一樣前移)
#include<stdio.h>
#include<string.h>
#define maxm 1000
typedef struct e{
char letter;/*字元(不包括)*/
int end;/*如果字元後面是*號,標記end為1*/
int fail;/*相當於π函式*/
}e;
typedef struct MAC{
int n;/*非*字元的個數*/
e p[maxm+1];
}MAC;
MAC initmac(void)
{
char p[maxm];
scanf("%s",p);
int i,l,k=0;
l=strlen(p);
MAC mac;
mac.p[0].end=1 ;/*特殊情況,置0*/
for (i=0;i<l;i++)
if (p[i]!='*')
{
k++;
mac.p[k].end=0;
mac.p[k].letter=p[i];
}
else
mac.p[k].end=1;
mac.n=k;
return mac;
}
int computfail(MAC *mac)/*這裡一定要用指標,因為結構作為引數傳遞時,是複製記憶體*/
{
int q,i;
int n=mac->n;
e *p=mac->p;
q=0;
for (i=1;i<=n;i++)
if (p[i].end)/*如果後面是*號,fail指向自己*/
{
p[i].fail=i;
q=i;
}
else
if (p[i-1].end)/*指向前面的最後一個字元,相當於KMP演算法中的初始化*/
{
p[i].fail=i-1;
q=i-1;
}
else/*和KMP演算法一樣,即對單個字串計算π函式*/
{
while ((!p[q].end)&&(p[q+1].letter!=p[i].letter))
q=p[q].fail;
if (p[q+1].letter==p[i].letter)
q++;
p[i].fail=q;
}
return 0;
}
int match(MAC *mac,char t[])/*和KMP演算法中的匹配幾乎一樣*/
{
int i,l=strlen(t),q=0;
int n=mac->n;
e *p=mac->p;
for (i=0;i<l;i++)
{
while ((!p[q].end)&&(p[q+1].letter!=t[i]))
q=p[q].fail;
if (p[q+1].letter==t[i])
q++;
if (q==n)
return 1;/*和書上的KMP匹配的時候不一樣,這裡直接退出即可,實際上不退出也只能找到前面相同,最後一個部分出現位置不同*/
}
return 0;
}
int main(void)
{
char t[maxm];
scanf("%s",t);
MAC mac;
mac=initmac();
computfail(&mac);
int ans;
ans=match(&mac,t);
printf("%d\n",ans);
return 0;
}
缺點是隻能找到一次出現的位置,要找到所有的位置,目前只知道遞迴搜尋…哎…