苏大编译原理实验二(构建NFA化至最简DFA)只用数组和栈

学习不好,数据结构课很遗憾没好好学,很遗憾很遗憾,所以不会用树也不会用列表,使用队列我更是自取其辱。。。。所以全篇只用到了数组和栈(以及最后的map)头文件引用得有点乱,对八起。

整体思路只要上学期认真上过编译原理课就应该明白,手动怎么画这里我们用电脑就怎么做,可以自己拿一个例子画一下复习复习。

需要的学弟学妹自取(注释基本都有,如果有什么不明白的我看到会回

然后如果需要的话这位大佬的写的超棒,虽然我没用,但是我先跪为敬。。。编译原理实验三:NFA确定化和DFA最小化_裕东方的博客-CSDN博客_nfa确定化和最小化

如果有大佬看见我的代码请帮忙改进一下!!!跪谢!

#include <iostream>
#include<string.h>
#include<stack>
#include<vector>
#include<map>
#define maxnum 100
using namespace std;
char putin[maxnum]="(a|b)*ab";
struct pointnode{
    int start[100];
    char trans[100];
    int end[100];
};
pointnode nfa[maxnum];
stack<char>charputin;
int beginnum=0;
int flag=0;
stack<int>doublepoint;
void createnfa(){
    int len=strlen(putin);
    int tempstrlen=0;
    for (int i=len-1;i>=0;--i){
        charputin.push(putin[i]);
    }
    while(!charputin.empty()){
        char tempchar=charputin.top();
        char tempstr[maxnum];
        if(tempchar=='('){
            charputin.pop();
            while(charputin.top()!=')'){
                tempstr[tempstrlen]=charputin.top();
                ++tempstrlen;
                charputin.pop();
            }
            charputin.pop();
            flag=1;
        }
        else if (flag==1){
            if (tempchar=='*'){
                nfa[beginnum].start[0]=beginnum;
                nfa[beginnum].start[1]=beginnum;
                nfa[beginnum].trans[0]='*';
                nfa[beginnum].trans[1]='*';
                nfa[beginnum].end[0]=beginnum+1;
                nfa[beginnum].end[1]=beginnum+7;//={beginnum,'*',++beginnum};
                doublepoint.push(beginnum);
                ++beginnum;
                flag=2;
                charputin.pop();
            }
            else{}
            nfa[beginnum].start[0]=beginnum;
            nfa[beginnum].trans[0]='*';
            nfa[beginnum].end[0]=beginnum+1;
            nfa[beginnum].start[1]=beginnum;
            nfa[beginnum].trans[1]='*';
            nfa[beginnum].end[1]=beginnum+3;
            doublepoint.push(beginnum);
            ++beginnum;
            for(int i=0;tempstr[i];++i){
                if (tempstr[i]!='|'){
                    nfa[beginnum].start[0]=beginnum;
                    nfa[beginnum].trans[0]=tempstr[i];
                    nfa[beginnum].end[0]=beginnum+1;
                    ++beginnum;
                }
                else{
                    nfa[beginnum].start[0]=beginnum;
                    nfa[beginnum].trans[0]='*';
                    nfa[beginnum].end[0]=beginnum+3;
                    ++beginnum;
                }
            }
            nfa[beginnum].start[0]=beginnum;
            nfa[beginnum].trans[0]='*';
            nfa[beginnum].end[0]=beginnum+1;
            ++beginnum;
            if(flag==2){
                nfa[beginnum].start[0]=beginnum;
                nfa[beginnum].trans[0]='*';
                nfa[beginnum].end[0]=beginnum+1;
                nfa[beginnum].start[1]=beginnum;
                nfa[beginnum].trans[1]='*';
                nfa[beginnum].end[1]=beginnum-5;
                doublepoint.push(beginnum);
                ++beginnum;
            }
            flag=0;
            tempstrlen=0;
        }
        else if (tempchar=='*'){
            nfa[beginnum].start[0]=beginnum;
            nfa[beginnum].trans[0]=nfa[beginnum-1].trans[0];
            nfa[beginnum].end[0]=beginnum+1;
            nfa[beginnum-1].trans[0]='*';
            nfa[beginnum-1].trans[1]='*';
            nfa[beginnum-1].start[1]=beginnum-1;
            nfa[beginnum-1].end[1]=beginnum+2;
            doublepoint.push(beginnum-1);
            ++beginnum;
            nfa[beginnum].start[0]=beginnum;
            nfa[beginnum].trans[0]='*';
            nfa[beginnum].end[0]=beginnum+1;
            nfa[beginnum].start[1]=beginnum;
            nfa[beginnum].trans[1]='*';
            nfa[beginnum].end[1]=beginnum-1;
            doublepoint.push(beginnum);
            ++beginnum;
            charputin.pop();
        }
        else{
            nfa[beginnum].start[0]=beginnum;
            nfa[beginnum].trans[0]=tempchar;
            nfa[beginnum].end[0]=beginnum+1;
            ++beginnum;
            charputin.pop();
        }
    }
}
bool ifdouble(int n){
    stack<int>tempstack;
    int flag=0;
    while(!doublepoint.empty()){
        if(doublepoint.top()!=n){
            tempstack.push(doublepoint.top());
            doublepoint.pop();
        }
        else{
            flag=1;
            break;
        }
    }
    while(!tempstack.empty()){
        doublepoint.push(tempstack.top());
        tempstack.pop();
    }
    if(flag==1){
        return true;
    }
    else{
        return false;
    }
}
//以上nfa完成,开始构造dfa。nfa节点总数为beginnum,查找是否是doublepoint为ifdouble()


struct condi{
    int condinum[maxnum];
    int end[2];
    int num;
};
condi dfa[maxnum];
int dfalen=0;
condi c;
void search(int l,char ch);
bool ifincondinum(condi c1,int n);
int ifindfa(condi c2);
int ifintempdfa(condi c2);
void createdfa(){
    for(int l=0;l<dfalen;++l){
        c.num=0;
        search(l,'a');//添上a的关联部分
        int c1num1=ifindfa(c);//检查是否是重合状态
        if (c1num1==-1){//如果该状态和前面无重合,则给予编号并加入母节点的end中
            dfa[dfalen].num=c.num;
            for (int i=0;i<dfa[dfalen].num;i++){
                dfa[dfalen].condinum[i]=c.condinum[i];
            }
            dfa[l].end[0]=dfalen;
            dfalen++;
        }
        else{//如果重合,则把重合的编号加入母节点end,并且把该状态删除
                dfa[l].end[0]=c1num1;
        }
        c.num=0;
        search(l,'b');
        int c2num1=ifindfa(c);
        if (c2num1==-1){
            dfa[dfalen].num=c.num;
            for (int i=0;i<dfa[dfalen].num;i++){
                dfa[dfalen].condinum[i]=c.condinum[i];
            }
            dfa[l].end[1]=dfalen;
            dfalen++;
        }
        else{
                dfa[l].end[1]=c2num1;
        }
    }
}
void search0(){//找出初始状态的所有节点
    int num1=0;//nfa某个节点必有一个终点
    int num2=0;//nfa该节点可能有第二个终点
    for(int i=0;i<dfa[0].num;i++){
        if (nfa[dfa[0].condinum[i]].trans[0]=='*'){//如果该节点的中转为*
            num1=nfa[dfa[0].condinum[i]].end[0];
            if (!ifincondinum(dfa[0],num1)){//如果这是一个新的节点,则加入状态中
                dfa[0].condinum[dfa[0].num]=num1;
                dfa[0].num++; 
            }
        }
        if(ifdouble(dfa[0].condinum[i])){//如果有两条支线,则看第二条线的内容
            if (nfa[dfa[0].condinum[i]].trans[1]=='*'){//同上
                num2=nfa[dfa[0].condinum[i]].end[1];
                if (!ifincondinum(c,num2)){
                    dfa[0].condinum[dfa[0].num]=num2;
                    dfa[0].num++;
                }
            }
        }
    }
}
void search(int l,char ch){//找出一个状态的所有节点
    int n=dfa[l].num;//本轮起始状态的节点数量
    int num1=0;//nfa某个节点必有一个终点
    int num2=0;//nfa该节点可能有第二个终点
    for(int i=0;i<n;++i){
        if (nfa[dfa[l].condinum[i]].trans[0]==ch or nfa[dfa[l].condinum[i]].trans[0]=='*' ){//如果该节点的中转之一为ch
            num1=nfa[dfa[l].condinum[i]].end[0];
            if (!ifincondinum(c,num1)){//如果这是一个新的节点,则加入状态中
                c.condinum[c.num]=num1;
                c.num++;
            }
        }
        if(ifdouble(dfa[l].condinum[i])){//如果有两条支线,则看第二条线的内容
            if (nfa[dfa[l].condinum[i]].trans[1]==ch or nfa[dfa[l].condinum[i]].trans[1]=='*'){//同上
                num2=nfa[dfa[l].condinum[i]].end[1];
                if (!ifincondinum(c,num2)){
                    c.condinum[c.num]=num2;
                    c.num++;
                }
            }
        }
    }
    n=c.num;
    for(int i=0;i<n;i++){
        if (nfa[c.condinum[i]].trans[0]=='*'){//如果该节点的中转为*
            num1=nfa[c.condinum[i]].end[0];
            if (!ifincondinum(c,num1)){//如果这是一个新的节点,则加入状态中
                c.condinum[c.num]=num1;
                c.num++;
            }
        }
        if(ifdouble(c.condinum[i])){//如果有两条支线,则看第二条线的内容
            if (nfa[c.condinum[i]].trans[1]=='*'){//同上
                num2=nfa[c.condinum[i]].end[1];
                if (!ifincondinum(c,num2)){
                    c.condinum[c.num]=num2;
                    c.num++;
                }
            }
        }
    }
    sort(c.condinum,c.condinum+c.num);
}
bool ifincondinum(condi c1,int n){//检查该终点(节点)是否已经在该状态中
    int f=c1.num;
    for (int i=0;i<f;++i){
        if (c1.condinum[i]==n){
            return true;
        }
    }
    return false;
}
int ifindfa(condi c2){//检查是否在dfa中
    for(int i=0;i<dfalen;i++){
        if (dfa[i].num==c2.num){
            int j;
            for(j=0;j<dfa[i].num;j++){
                if(c2.condinum[j]!=dfa[i].condinum[j]){
                    break;
                }
            }
            if(j==dfa[i].num){
                return i;
            }
        }
    }
    return -1;
}
int jumpnum[maxnum];
int countjump=0;
int endnum[maxnum];
int countend=0;
bool injumpnum(int n){
    for(int k=0;k<countjump;++k){
        if (jumpnum[k]==n){
            return true;
        }
    }
    return false;
}
bool inendnum(int n){
    for(int k=0;k<countend;++k){
        if (endnum[k]==n){
            return true;
        }
    }
    return false;
}
void simplify(){
    for(int i=0;i<dfalen;++i){
        if (!ifincondinum(dfa[i],beginnum) and !injumpnum(i)){
            for(int j=i+1;j<dfalen;++j){
                if(dfa[j].end[0]==dfa[i].end[0]and dfa[j].end[1]==dfa[i].end[1] and (!ifincondinum(dfa[j],beginnum))){
                    //将所有出现过的jumpnum都换掉
                    for(int a=0;a<dfalen;++a){
                        if( dfa[a].end[0]==j){
                            dfa[a].end[0]=i;
                        }
                        else if (dfa[a].end[1]==j){
                            dfa[a].end[1]=i;
                        }
                    }
                    jumpnum[countjump]=j;//j会被跳过
                    countjump++;
                }
            }
        }
        else if (ifincondinum(dfa[i],beginnum)){
            endnum[countend]=i;
            countend++;
        }
    }
}

int main(){
    createnfa();
    dfa[dfalen].num=0;
    dfa[dfalen].condinum[0]=0;
    dfa[dfalen].num++;
    search0();//初始状态A完成,接下来二三搜索B,C
    sort(dfa[0].condinum,dfa[0].condinum+dfa[0].num);
    dfalen++;
    createdfa();
    //for(int i=0;i<dfalen;++i){
      //      cout<<i<<" a:"<<dfa[i].end[0]<<" b:"<<dfa[i].end[1]<<endl;
    //}
    simplify();
    map<int,char>asc;
    char prepareforuse[26]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
    int ascnum=0;
    for(int i=0;i<dfalen;++i){
        if(!injumpnum(i)){
            asc.insert(pair<int,char>(i,prepareforuse[ascnum]));
            ascnum++;
        }
    }
    cout<<"以下为最简dfa"<<endl;
    for(int i=0;i<dfalen;++i){
        //cout<<i<<endl;
        if(!injumpnum(i)){
            cout<<asc[i]<<" a:"<<asc[dfa[i].end[0]]<<" b:"<<asc[dfa[i].end[1]]<<endl;
        }
    }
    int cinlen;
    cin>>cinlen;
    char cinchar[cinlen];
    cin>>cinchar;
    int getstart=0;
    for(int i=0;i<cinlen;++i){
        if(cinchar[i]=='a'){
            getstart=dfa[getstart].end[0];
        }
        else{
            getstart=dfa[getstart].end[1];
        }
    }
    if (inendnum(getstart)){
        cout<<"符合"<<endl;
    }
    else{
        cout<<"不符合"<<endl;
    }
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值