【编译原理】NFA转DFA(子集构造法)

前文回顾

【编译原理】正则表达式转NFA
 

算法

来自龙书第二版
在这里插入图片描述

C++实现

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#define MAX_TRANS 100
using namespace std;

vector<char>characters;//输入字符集
int DFA_state_number=0;//DFA中状态数量
vector<vector<int>>transition(MAX_TRANS);//记录终态的名称变化(一对多)
int final_count=0;//终态数量
int trans_count=0;//transition大小

//得到的状态集合
struct States
{
    vector<int>jset;
};

//DFA状态转换关系
struct relation
{
    States* pre;
    char jchar;
    States* next;
};
//得到s闭包
void Eclosure(bigCell NFA,States *s)
{
    for(int i=0;i<s->jset.size();i++)
    {
        for(int j=0;j<NFA.count;j++)
        {
            if(NFA.edges[j].source.id==s->jset[i] && NFA.edges[j].symbol=='?')
            {
                s->jset.push_back(NFA.edges[j].target.id);
            }
        }
    }
}
//能够从状态集s出发通过字符tc转换到达的NFA状态集合,结果放在t中
void move(char tc,bigCell NFA,States* s,States* t)
{
    for(int i=0;i<s->jset.size();i++)
    {
        for(int j=0;j<NFA.count;j++)
        {
            if(NFA.edges[j].source.id==s->jset[i] && NFA.edges[j].symbol==tc)
                t->jset.push_back(NFA.edges[j].target.id);
        }
    }
}
//添加状态子集
bool add(vector<States*>allSet,States *newS)
{
    bool b=true;
    for(int i=0;i<allSet.size();i++)
    {
        if(allSet[i]->jset==newS->jset)
            b=false;
    }
    return b;
}
//去除重复的DFA转换关系
bool addRel(vector<relation*>relVec,States* preS,char c,States*nextS)
{
    bool b=true;
    for(int i=0;i<relVec.size();i++)
    {
        if(relVec[i]->pre->jset==preS->jset && relVec[i]->next->jset==nextS->jset
           && relVec[i]->jchar==c)
           b=false;
    }
    return b;
}

//状态名称合并并重命名
void Rename(vector<States*>allSet,States* tS,int &newS)
{
    //从1开始命名
    for(int i=0;i<allSet.size();i++)
    {
        if(tS->jset==allSet[i]->jset)
            newS=i+1;
    }
}

//数组去重
void only(int *a,int n,int* b)
{
    memset(b,0,sizeof(int)*n);
    char first=a[0];
    for(int i=0;i<n;i++)
    {
        b[a[i]-first]=a[i];
    }
    final_count=a[n-1]-first+1;
}

//主要函数
int* NFA2DFA(bigCell NFA,vector<vector<int>>&dfaT)
{
    States *newS=new States();
    newS->jset.push_back(NFA.start.id);//初始状态
    Eclosure(NFA,newS);//得到初始状态的闭包I
    vector<States*>allSet(1,newS);//DFA所有状态集合,初值为I的Eclosure

    int sizeOfStrVec=1;

    vector<States*>strVec(1,newS);//存储每次闭包操作多出的状态集合
    vector<relation*>relVec;//状态转换关系的集合

    //还有新增状态
    while(sizeOfStrVec)
    {
        int oldAllSet=allSet.size();//原本所有状态数
        for(int j=0;j<sizeOfStrVec;j++)
        {
            //cout<<j;

            //遍历所有输入字符
            for(int i=0;i<NFA.count;i++)
            {
                States *dest=new States();

                //含有输入字符的边
                if(NFA.edges[i].symbol!='?')
                {
                    move(NFA.edges[i].symbol,NFA,strVec[j],dest);//从strVec[j]出发通过symbol到达的所有状态存在dest中
                    Eclosure(NFA,dest);//U=dest

                    //U不在状态总集中
                    if(add(allSet,dest)&&dest->jset.size()!=0)
                    {
                        allSet.push_back(dest);
                    }

                    //将U加入DFA转换关系中
                    if(dest->jset.size()!=0)
                    {
                        relation* rDest=new relation();
                        rDest->pre=strVec[j];
                        rDest->jchar=NFA.edges[i].symbol;
                        rDest->next=dest;

                        //新的转换关系不与已有的重复,则加入relVec
                        bool isIn=addRel(relVec,rDest->pre,rDest->jchar,rDest->next);
                        if(isIn)
                        {
                            relVec.push_back(rDest);
                        }
                    }
                }
            }
        }

        //将新增状态加入strVec中
        strVec.clear();
        int newAllSet=allSet.size();
        for(int i=oldAllSet;i<allSet.size();i++)
        {
            States* dest=new States();
            dest=allSet[i];
            strVec.push_back(dest);
        }
        sizeOfStrVec=strVec.size();
    }

    /*加上以下代码可输出转换过程*/
//    cout<<"状态转换如下:"<<endl;
//    vector<relation*>::iterator it;
//    for(it=relVec.begin();it!=relVec.end();it++)
//    {
//        输出转换前状态
//        for(int i=0;i<(*it)->pre->jset.size()-1;i++)
//        {
//            cout<<(*it)->pre->jset[i]<<",";
//        }
//
//        输出输入字符
//        cout<<(*it)->pre->jset[(*it)->pre->jset.size()-1]<<"     "<<(*it)->jchar<<"     ";
//
//        输出转换后状态
//        for(int i=0;i<(*it)->next->jset.size()-1;i++)
//        {
//            cout<<(*it)->next->jset[i]<<",";
//        }
//        cout<<(*it)->next->jset[(*it)->next->jset.size()-1]<<endl;
//    }
//    cout<<endl;
//
//    输出状态重命名前后名称
//    int newName[MAX];
//    memset(newName,0,sizeof(char)*MAX);
//    cout<<"状态重命名如下:"<<endl;
//    for(int i=0;i<allSet.size();i++)
//    {
//        newName[i]=i+1;
//        cout<<newName[i]<<":";
//        for(int j=0;j<allSet[i]->jset.size()-1;j++)
//        {
//            cout<<allSet[i]->jset[j]<<",";
//        }
//        cout<<allSet[i]->jset[allSet[i]->jset.size()-1]<<endl;
//    }
    DFA_state_number=allSet.size();

    vector<relation*>DFA;
    //创建重命名后的新边集合
    for(int i=0;i<relVec.size();i++)
    {
        relation* newRel=new relation();
        //改名
        int newPre,newNext;
        Rename(allSet,relVec[i]->pre,newPre);
        Rename(allSet,relVec[i]->next,newNext);
        //创建新边
        States* tpre=new States();
        States* tnext=new States();
        newRel->pre=tpre;
        newRel->next=tnext;
        newRel->pre->jset.push_back(newPre);
        newRel->next->jset.push_back(newNext);
        newRel->jchar=relVec[i]->jchar;
        DFA.push_back(newRel);

    }

    vector<relation*>::iterator rit;
    for(rit=DFA.begin();rit!=DFA.end();rit++)
    {
        dfaT[(*rit)->pre->jset[0]][(*rit)->jchar]=(*rit)->next->jset[0];
        characters.push_back((*rit)->jchar);
    }
    //去除字符集重复元素
    sort(characters.begin(),characters.end());
    characters.erase(unique(characters.begin(), characters.end()), characters.end());

    //终态
    int l=allSet.size();
    int *accepted=new int[l];
    //memset(accepted,0,sizeof(int)*l);
    for(int i=0;i<l;i++)
    {
        for(int j=0;j<allSet[i]->jset.size();j++)
        {
            //cout<<allSet[i]->jset[j]<<endl;
            for(int k=0;k<NFA.end.size();k++)
            {
                if(allSet[i]->jset[j]==NFA.end[k].id)
                {
                    accepted[final_count++]=i+1;
                    transition[i+1].push_back(NFA.end[k].id);//记录终态重命名前后
                    trans_count=i+2;
                    //cout<<i+1<<" "<<transition[i+1][1]<<endl;
                }
            }
        }
    }
    int *outs=new int[final_count];
    only(accepted,final_count,outs);
    delete []accepted;
    delete newS;
    return outs;
}
int showDFA(vector<vector<int>>dfaT,int *accepted)
{
    cout<<"DFA信息:"<<endl;
    for(int i=1;i<=DFA_state_number;i++)
    {
        for(int j=0;j<characters.size();j++)
        {
            char c=characters[j];
            cout<<i<<" "<<c<<" "<<dfaT[i][c]<<endl;
        }
    }

    cout<<"可接受状态为:"<<endl;
    for(int i=0;i<final_count;i++)
    {
        cout<<accepted[i]<<" ";
    }
    cout<<endl<<endl;
}

 

测试结果

输出结果为:DFA每一条边的 起点 转换字符 终点
在这里插入图片描述
在这里插入图片描述
P.S:要源码的人太多了,贴下百度网盘的链接,有需要的自己去下载吧
链接:https://pan.baidu.com/s/1oQhPT26zVZFLCabot0tk_g
提取码:gtdv
 

其他相关博文

词法分析

【编译原理】正则表达式转NFA
【编译原理】最小化DFA

语法分析

【编译原理】LR(0)分析方法(c++实现)
【编译原理】SLR(1)分析方法(c++实现)
【编译原理】LL(1)分析方法 生成语法树(c++实现)

  • 11
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值