1. 程式人生 > >32.3-5帶有萬用字元的匹配(自動機)

32.3-5帶有萬用字元的匹配(自動機)

功能

這個程式可以判斷一個帶有萬用字元*的模式串是否在文字串中存在,沒有記錄位置資訊,當然,想記錄也是可以的

樣例輸入:
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; }

缺點是隻能找到一次出現的位置,要找到所有的位置,目前只知道遞迴搜尋…哎…