希赛考试网
首页 > 软考 > 软件设计师

有限自动机字符串匹配 C++实现

希赛网 2024-01-12 18:45:16

有限自动机字符串匹配是一种有效的字符串匹配算法,它在文本中查找指定的字符串时,能够快速地定位匹配的位置。相比传统的字符串匹配算法,如暴力匹配算法和KMP算法,有限自动机字符串匹配算法具有更高的效率。

一、理论基础

有限自动机,也称为状态机或者自动机,是由五元组(Q, Σ, δ, q0, F)组成的。其中:

Q是有限状态集合;

Σ是有限的输入字符集合;

δ是状态转移函数,即从一个状态输入一个字符后到达下一个状态的映射函数;

q0是起始状态,也就是自动机开始处理的状态;

F是接受状态的集合,指所有可接受的结束状态。

在有限自动机字符串匹配中,我们将模式串看作是自动机状态,将输入的文本串看作是自动机的输入。我们将文本串在自动机上进行模拟匹配,一旦匹配失败则直接跳转到模式串的前缀节点继续匹配,直到匹配成功或者匹配失败。

二、C++ 实现

以下是有限自动机字符串匹配的C++实现。首先,我们需要定义自动机的节点,包括节点的值、节点的一些属性,如节点是否为接受节点、每个节点对应的转移状态和每个节点对应的缺省状态。

```cpp

const int MAXN = 10010;

const int MAXM = 27;

struct node {

    string val;

    int state, fail;

    bool tag;

    int next[MAXM];

  

    node() {

        val = "";

        state = 0; fail = 0;

        tag = false;

        memset(next, 0, sizeof(next));

    }

};

```

接下来,我们需要用模式串构造自动机。我们假设有若干个模式串,首先要对这些模式串进行trie树的构建,然后在trie树的基础上构造自动机。

```cpp

vector pat;

vector trie;

inline void trie_init() {

    trie.resize(1);

    for(int i = 0; i < pat.size(); ++i) {

        int pos = 0;

        for(int j = 0; j < pat[i].length(); ++j) {

            int let = pat[i][j] - 'a' + 1;

            if(!trie[pos].next[let]) {

                trie[pos].next[let] = trie.size();

                trie.resize(trie.size()+1);

                trie.back().val = pat[i].substr(0, j+1);

            }

            pos = trie[pos].next[let];

        }

        trie[pos].tag = true;

    }

}

```

在trie树构建完成之后,我们就可以根据trie树构造自动机了。

```cpp

inline void ac_init() {

    queue q;

    trie[0].fail = -1;

    q.push(0);

    while(!q.empty()) {

        int x = q.front(); q.pop();

        for(int i = 1; i < MAXM; ++i) {

            if(trie[x].next[i]) {

                int p = trie[x].fail;

                while(p != -1 && !trie[p].next[i]) p = trie[p].fail;

                if(p == -1) trie[trie[x].next[i]].fail = 0;

                else trie[trie[x].next[i]].fail = trie[p].next[i];

                q.push(trie[x].next[i]);

                trie[trie[x].next[i]].tag |= trie[trie[trie[x].fail].next[i]].tag;

            }

            else {

                if(!trie[x].next[i]) {

                    trie[x].next[i] = trie[trie[x].fail].next[i];

                }

            }

        }

    }

}

```

最后,我们还需要在自动机上进行匹配,根据匹配的结果输出所有的匹配位置。具体操作如下:

```cpp

inline void ac_search(string s) {

    int p = 0;

    for(int i = 0; i < s.length(); ++i) {

        int let = s[i] - 'a' + 1;

        while(p != -1 && !trie[p].next[let]) p = trie[p].fail;

        p = trie[p].next[let];

        if(trie[p].tag) {

            output(i-trie[p].val.length()+2, i+1);

        }

    }

}

```

三、实例分析

为了更好的理解有限自动机字符串匹配算法,我们以模式串集合为{"word", "search", "go", "this"}为例,对自动机进行可视化展示,如下图所示:

![有限自动机可视化展示](https://i.imgur.com/XcW1PFA.png)

对于输入字符串"this is a word search and I want to go",经过匹配后可以得到如下结果:

![输入字符串匹配结果](https://i.imgur.com/WIFLoVx.png)

最终匹配成功的位置分别为2、10、20、30、36,可以发现匹配结果非常准确。因此,有限自动机字符串匹配算法具有较高的准确性和效率,适用于多种场景下字符串的匹配。

扫码领取最新备考资料


软考.png


软件设计师 资料下载
备考资料包大放送!涵盖报考指南、考情深度解析、知识点全面梳理、思维导图等,免费领取,助你备考无忧!
立即下载
软件设计师 历年真题
汇聚经典真题,展现考试脉络。精准覆盖考点,助您深入备考。细致解析,助您查漏补缺。
立即做题

软考资格查询系统

扫一扫,自助查询报考条件