DFA


layout: post
title: "DFA"
date: 2017-10-8 15:52:00 +0800
categories: Algorithm
tags: DFA
author: SteveDevin

mathjax: true

  • content
    {:toc}

最近编译原理课学了DFA, 想起去年暑假学的DFA模式串匹配还没写过, 就趁机写一下了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std;

const int LETTERS = 26;
const int maxn = 200 + 2;

struct TreeNode
{
    TreeNode* child[LETTERS];
    TreeNode* prev;
    bool badNode;

    TreeNode(bool bad = false, TreeNode *p = NULL):badNode(bad), prev(p)
    {
        memset(child, 0, sizeof(child
    }
}Tree[maxn];
int nTreeNode = 0;

void BuildTree(const char *s, TreeNode *p)
{
    for(int i = 0; s[i]; i++)
    {
        if(!p->child[s[i] - 'a'])
            p->child[s[i] - 'a'] = Tree + nTreeNode++;
        p = p->child[s[i] - 'a'];
    }
    p->badNode = true;
}

void BuildDfa(TreeNode *Tree)
{
    for(int i = 0; i < LETTERS; i++)
        Tree[0].child[i] = Tree + 1;
    Tree[0].prev = NULL;
    Tree[1].prev = Tree;

    deque<TreeNode *> q;
    q.push_back(Tree + 1);

    while(!q.empty())
    {
        TreeNode *pRoot = q.front();
        q.pop_front();

        for(int i = 0; i < LETTERS; i++)
        {
            TreeNode *p = pRoot->child[i];
            if(p)
            {
                TreeNode *pPrev = pRoot->prev;
                while(pPrev)
                {
                    if(pPrev->child[i])
                    {
                        p->prev = pPrev->child[i];
                        if(p->prev->badNode) p->badNode = true;
                        break;
                    } else pPrev = pPrev->prev;
                }
                q.push_back(p);
            }
        }
    }
}

bool SearchDfa(TreeNode *Tree, const char *s)
{
    TreeNode *p = Tree + 1;

    for(int i = 0; s[i]; i++)
    {
        while(true)
        {
            if(p->child[s[i] - 'a'])
            {
                p = p->child[s[i] - 'a'];

                if(p->badNode) return true;
                break;
            }else p = p->prev;
        }
    }
    return false;
}

int main()
{
    int N, M;
    cin >> N >> M;

    nTreeNode = 2;

    for(int i = 0; i < N; i++)
    {
        string s;
        cin >> s;
        BuildTree(s.c_str(), Tree + 1);
    }

    BuildDfa(Tree);

    for(int i = 0; i < M; i++)
    {
        string s;
        cin >> s;
        cout << (SearchDfa(Tree, s.c_str()) ? "True" : "False") << endl;
    }

    system("pause");
}

测试结果:

2 2
abc
def
deababcdef
True
deababb
False

写一个可以求出具体位置的版本(正确性待验证):

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <deque>
using namespace std;

// !!!!  input range in 'a' to 'z'

const int maxn = 200 + 2;
const int LETTERS = 26;

struct TreeNode {
    TreeNode *child[LETTERS];
    TreeNode *prev;
    bool badNode;
    int deep;

    TreeNode() :prev(NULL), badNode(false), deep(0)
    {
        memset(child, 0, sizeof(child));
    }
}Tree[maxn];
int nTreeNode = 0;

void BuildTree(TreeNode *pRoot, char *s)
{
    for (int i = 0; s[i]; i++)
    {
        if (!pRoot->child[s[i] - 'a'])
            pRoot->child[s[i] - 'a'] = Tree + nTreeNode++;
        pRoot->child[s[i] - 'a']->deep = pRoot->deep + 1;
        pRoot = pRoot->child[s[i] - 'a'];
    }
    pRoot->badNode = true;
}

void BuildDfa(TreeNode *Tree)
{
    for (int i = 0; i < LETTERS; i++)
        Tree->child[i] = Tree + 1;
    Tree[0].prev = NULL;
    Tree[1].prev = Tree;

    deque<TreeNode *> q;
    q.push_back(Tree + 1);

    while (!q.empty())
    {
        TreeNode *pRoot = q.front();
        q.pop_front();

        for (int i = 0; i < LETTERS; i++)
        {
            if (pRoot->child[i])
            {
                TreeNode *pPrev = pRoot->prev;
                while (pPrev)
                {
                    if (pPrev->child[i])
                    {
                        pRoot->child[i]->prev = pPrev->child[i];
                        if (pRoot->child[i]->prev->badNode)
                        {
                            pRoot->child[i]->badNode = true;
                        }
                        break;
                    }else pPrev = pPrev->prev;
                }
                q.push_back(pRoot->child[i]);
            }
        }
    }
}

int SearchDfa(TreeNode *Tree, char *s)
{
    TreeNode *p = Tree + 1;
    for (int i = 0; s[i]; i++)
    {
        while (true)
        {
            if (p->child[s[i] - 'a'])
            {
                p = p->child[s[i] - 'a'];
                if (p->badNode) return i - p->deep + 1;
                break;
            }p = p->prev;
        }
    }
    return -1;
}

int main()
{
    int N, M;
    nTreeNode = 2;
    scanf("%d%d", &N, &M);

    char s[maxn];
    for (int i = 0; i < N; i++)
    {
        scanf("%s", s);
        BuildTree(Tree + 1, s);
    }

    BuildDfa(Tree);

    for (int i = 0; i < M; i++)
    {
        scanf("%s", s);
        int ret = SearchDfa(Tree, s);
        if (ret < 0)
            cout << "NOT FOUND" << endl;
        else cout << ret << endl;
    }
}

转载于:https://www.cnblogs.com/QQ-1615160629/p/DFA.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 实验内容 每一个正规集都可以由一个状态数最少的DFA所识别,这个DFA是唯一的(不考虑同构的情况)。任意给定的一个DFA,根据以下算法设计一个C程序,将该DFA 化简为与之等价的最简DFA。 2. 实验设计分析 2.1 实验设计思路 根据实验指导书和书本上的相关知识,实现算法。 2.2 实验算法 (1)构造具有两个组的状态集合的初始划分I:接受状态组 F 和非接受状态组 Non-F。 (2)对I采用下面所述的过程来构造新的划分I-new. For I 每个组G do Begin 当且仅当对任意输入符号a,状态s和读入a后转换到I的同一组; /*最坏情况下,一个状态就可能成为一个组*/ 用所有新形成的小组集代替I-new的G; end (3)如果I-new=I,令I-final=I,再执行第(4)步,否则令I=I=new,重复步骤(2)。 (4)在划分I-final的每个状态组选一个状态作为该组的代表。这些代表构成了化简后的DFA M'状态。令s是一个代表状态,而且假设:在DFA M,输入为a时有从s到t转换。令t所在组的代表是r,那么在M’有一个从s到r的转换,标记为a。令包含s0的状态组的代表是M’的开始状态,并令M’的接受状态是那些属于F的状态所在组的代表。注意,I-final的每个组或者仅含F的状态,或者不含F的状态。 (5)如果M’含有死状态(即一个对所有输入符号都有刀自身的转换的非接受状态d),则从M’去掉它;删除从开始状态不可到达的状态;取消从任何其他状态到死状态的转换。 。。。。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值