代码改变世界

利用有限自动机进行字符串匹配

2014-09-04 11:27  微尘_无名  阅读(362)  评论(0编辑  收藏  举报

利用有限自动机进行字符串匹配关键在于在预处理阶段计算出状态转移函数delta。假设m是模式P的长度,则一共有从0到m一共(m + 1)个状态,计算每个状态转移到字母表∑*中任意字母之后的状态,时间复杂度是O(m3|∑|)。最后利用利用自动机来对输入文本T进行一遍扫面,如果在扫描到字符T[i]是有当前状态q == m,说明找到一个匹配。因此可以找出所有的匹配,时间复杂度为Φ(n)。

原理相对简单,在此给出代码实现:

#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

//transition_function
int const MAX_N = 1000;
int delta[MAX_N][MAX_N];  //用delta模拟状态转移函数
char minChar;             //当前字母表的最小字符,每个字符减去这个minChar来映射到数组的从0开始的下标



bool is_postfix(string& Pk, string& Pqa)
{
    if(Pk.length() > Pqa.length())
        return false;
    for(int i = 0; i < Pk.length(); i++)
    {
        if(Pk[i] != Pqa[Pqa.length() - Pk.length() + i])
            return false;
    }
    return true;
}

void COMPUTE_TRANSITION_FUNCTION(string& P, string& Sigma)
{
    int m = P.length();
    minChar = *min_element(Sigma.begin(), Sigma.end());
    for(int q = 0; q <= m; q++)
    {
        for(int j = 0; j < Sigma.length(); j++)
        {
            char a = Sigma[j];
            int k = min(m + 1, q + 2);
            for(;;)
            {
                k--;
                if(is_postfix(P.substr(0, k), P.substr(0, q) + a))
                    break;
            }
            delta[q][a - minChar] = k;
        }
    }
}

void FINITE_AUTOMATION_MATCHER(string& T, int m)
{

    int n = T.length();
    int q = 0;
    for(int i = 0; i <n ; i++)
    {
        q = delta[q][T[i] - minChar];
        if(q ==  m)
            cout<<"Pattern occurs with shift "<<i + 1 - m <<endl;
    }
}

int main()
{
    string T = "abababacaba";
    string P = "ababaca";
    string Sigma = "abc";
    COMPUTE_TRANSITION_FUNCTION(P,Sigma);
    FINITE_AUTOMATION_MATCHER(T, P.length());
    return 0;
}
View Code