字符串匹配

来源:互联网 发布:数据库导论第五版答案 编辑:程序博客网 时间:2024/06/08 13:16

字符串匹配


问题描述

  • 输入两个字符串A和B;

  • 输出字符串B在字符串A中的位置。

示例

  • 输入字符串“ABDABACDBD”和字符串“BACD”;

  • 输出偏移量5,或输出在第一个字符串中“BACD”处的指针。

方法

  • 常用方法有好多:朴素算法Rabin-Karp算法有限自动机算法KMP算法

  • 复杂度对比:复杂度为预处理时间匹配时间的和。

    算法预处理时间匹配时间朴素算法0Ο((n-m+1)*m)Rabin-Karp算法Θ(m)Ο((n-m+1)*m)有限自动机算法Ο(m*字符集个数)Θ(m)Knuth-Morris-Prattu算法Θ(m)Θ(m)Boyer–Moore算法待搜索待搜索

朴素算法

  • 通过循环找到所有有效偏移;

  • 函数NaiveStringMatcher(char *A,char *T)实现在字符串A中匹配字符串T;

  • 辅助函数CharacterMatcher(char *A,char *B,char *T)判断指针A和B之间字符串是不是和字符串T匹配。

    bool CharacterMatcher(char *A,char *B,char *T){char *cc = A;int i = 0;while(cc != B){if(*cc != *(T+i))return false;cc++;i++;}return true;}void NaiveStringMatcher(char *A,char *T){int iLengthofA = strlen(A);int iLengthofT = strlen(T);for(int i = 0;i <= iLengthofA-iLengthofT ;i++){if(CharacterMatcher(A+i,A+i+iLengthofT,T))cout<<"Pattern occurs with shift"<< i+1 << endl;}}

Rabin-Karp算法1

  • 将字符串做一种数的运算得到一个值,然后进行值的比较;

  • 这个数值要求可以表示出字符的前后顺序,而且可以随时去掉某个字符的值,可以随时添加一个新字符的值。

  • 例如A="12345",B="34",对于B采用运算(3*10+4)得到34作为B的值;采用相同运算方式对A进行运算,然后做比较。

  • 如果相乘过大时,可以对一个较大的素数求模,然后比较。

    double Encryption(char *A, int m,int q){int i =0;double sum = 0.0;while(i < m){sum = sum * q + ((int)*(A + i++)) ;}return sum;}int ChangeEncryption(char *A,int ll,int sum,int q){double mm = pow((double)q,(double)ll - 1);return ((sum - (int)mm * (*A)) * q + *(A + ll));}char * Rabin_Karp_Algo(char *A,char *B){int ll = strlen(B);double m = Encryption(B ,ll, 128);double n = Encryption(A ,ll, 128);char *cc = A;for(;*(cc+ll) != '\0';cc++){if(n == m){return cc;}n = ChangeEncryption(cc,ll,n,128);}return NULL;}

有限自动机算法2

  • 在字符串A中搜索模式T,对于模式T中出现的所有可能情况看作不同状态。

  • 如模式T为“ababaca”

  • 建立状态0~7,分别对应{初始状态}、{a}、{ab}、{aba}、{abab}、{ababa}、{ababac}、{ababaca}。

  • 计算对应状态转移表(计算方法后面讲到)。

    static int delta[8][4]={  //转移函数  检测ababaca//a,b,c,*.{1,0,0,0},  //状态0   {初始状态}{1,2,0,0},  //状态1   {a,}{3,0,0,0},  //状态2   {ab,}{1,4,0,0},  //状态3   {aba,}{5,0,0,0},  //状态4   {abab,}{1,4,6,0},  //状态5   {ababa,}{7,0,0,0},  //状态6   {ababc,}{1,2,0,0}   //状态7   {ababca,}};int State = 0;  //初试状态
  • 函数AutomationMatch(char *A)为匹配函数,返回位置指针。

    char *AutomationMatch(char *A){int Length = strlen(A);char *cc = A;while(*cc != '\0'){int n = *cc++ - 'a';if(n != 0 && n != 1 && n != 2)n = 3;State = delta[State][n];if(State == 7)return cc-7;}return NULL;}
  • 状态转移表计算

  • 根据给定模式T[1..m]来计算。

  • 伪代码为

    COMPUTE-TRANSITION-FUNCTION(T,E)1   m=P.length2   for q = 0 to m3   for each charater a∈E4   k = MIN(m+1,q+1)5   repeat6   k = k - 17   until T[1..k] is tail of T[1..q]&a8   δ(q,a) = k9   return δ
  • c++代码

    bool TT(char *T,int k,int q,char a){if(*(T + k-- - 1) != a)return false;while(k > 0 && q > 0){if(*(T + k - 1) != *(T + q - 1))return false;k--;q--;}return true;}int *TransitionFunction(char *T,char *E) //T为搜索模式,E为T的字符集{const int m = strlen(T);const int n = strlen(E);int *Ans[8][3];int q = 0,p = 0;int k = 0;for(;q <= m;q++){for(p = 0;p < n;p++){k = MIN(m+1,q+1);while(!TT(T,k,q,*(E+p)) && k>0){k = k-1;}*((int*)Ans + n * q + p) = k;}}return (int*)Ans;}

KMP算法3

  • 详细解释看参考

  • 代码

    int *ComputePrefixFunction(char *P){int i = 1;int j = 0;int m = strlen(P);int *s = new int[m];memset(s,0,m * 8);while(i < m){while(P[i] == P[j] && i < m ){s[i] = s[i-1] + 1;j++;i++;}j = 0;i++;}return s;}void KMPMatcher(char *T,char *P){int n = strlen(T);int m = strlen(P);int q = 0;int *Map = ComputePrefixFunction(P);int i;for(i = 0 ; i < n ; i++){while(q > 0 && P[q] != T[i])q = Map[q-1];if(P[q] == T[i])q++;if(q == m){int gg = i -m +1 ;cout << "zhongduan:" << ends;printf("%d",gg);q = Map[q - 1];}}}

by:狼儿乖乖

time:2015/1/19 20:51:43


  1. http://www.cnblogs.com/golove/p/3234673.html ↩

  2. http://www.cnblogs.com/skyivben/archive/2009/05/21/1474398.html ↩

  3. http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html ↩


0 0
原创粉丝点击