编译原理(二) NFA的确定化及DFA的最小化的算法及C++实现

1. NFA的确定化

1.1. 明确NFA的定义

一个非确定的有穷自动机(NFA)M是一个五元式:

  • M=(S,,δ,S0,F)  
    • S
    • δS×Sδ:S×2S
    • S0S,
    • F  S , 是一个终态集(可空)

1.2. 定义运算

定义对状态集合I的几个有关运算:

  • 状态集合I的 ε -闭包,表示为 ε -closure(I),定义为一状态集,是状态集I中的任何状态s经任意条 ε 弧而能到达的状态的集合。状态集合I的任何状态s都属于 ε -closure(I)。
  • 状态集合I的a弧转换,表示为move(I,a)定义为状态集合J,其中J是所有那些可从I的某一状态经过一条a弧而到达的状态的全体。 
    定义Ia =  ε -closure(move(I,a))

1.3. 算法描述

  • 每次从队头取出一个集合,(开始队列内只有初态集合I的 ε -闭包(I) ),然后得到它对于任意一个字符a的 Ia=εclosure(move(I,a))
  • 然后如果当前状态之前没有出现过,那么当前状态作为一个新的状态I,放入队列。
  • 一直做如上操作,直到队列为空

1.4. 代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <fstream>
#include <queue>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#define MAX 500
#define M 1000007

using namespace std;

struct Set
{
    set<int> elements;
    int state;
}I[MAX];

vector<int> e[MAX];
vector<int> edge[MAX];
vector<int> val1[MAX];
vector<int> val2[MAX];
vector<int> hash[M];
vector<int> types;
int vis[MAX][MAX];
int cntp,cnts,start,finish,used[MAX];

void _clear( );
void clear( );
void _add( int u , int v , int x );
void add( int u , int v , int x );
void dfs ( set<int>& elements , int u , int d , int flag );
void ensure();
void minimize();
int get_hash( set<int>& item );

//#define DEBUG

int main ( )
{
    int m;
    puts("给出NFA的边的条数:");
    while ( ~scanf ( "%d" , &m ) )
    {
        _clear();
        clear();
        puts("给出NFA的始态和终态:");
        scanf ( "%d%d" , &start , &finish );
        puts("给出所有的边,每行一条:");
        for ( int i = 0 ; i < m ; i++ )
        {
            int u,v,x;
            scanf ( "%d%d%d" , &u , &v , &x );
            _add ( u , v , x ); 
        }
#ifdef DEBUG
        set<int> temp;
        int num[]={2,3,6,7,8};
        //for ( int i = 2 ; i < 6 ; i++ )
        //    dfs ( temp , i , 0 , 2 );
        for ( int i = 0 ; i < 5 ; i++ )
            dfs ( temp , num[i] , 0 , 1 );
        set<int>::iterator it = temp.begin();
        for ( ; it != temp.end() ; it++ )
            printf ( "%d " , *it);
        puts("");
#else 
        ensure();
        puts("计算结果如下:");
        printf ( "%d\n" , cnts );
        for ( int i = 0 ; i < cnts ; i++ )
            for ( int j = 0 ; j < edge[i].size() ; j++ )
                printf ( "edges : %d %d %d\n" , i , edge[i][j] , val2[i][j] );
        puts("\n给出DFA的边的条数:");
#endif
    }
}

void _clear()
{
    for ( int i = 0 ; i < MAX ; i++ )
    {
        e[i].clear();
        val1[i].clear();
    }
    types.clear();
    memset ( used , 0 , sizeof ( used ) );
}

void clear()
{
    for ( int i = 0 ; i < MAX ; i++ )
    {
        edge[i].clear();
        val2[i].clear();
    }
}

void _add ( int u , int v , int x )
{
    e[u].push_back ( v );
    val1[u].push_back ( x );
    if ( !used[x] )
    {
        types.push_back ( x );
        used[x] = types.size();
    }
}

int get_hash ( set<int>& item )
{
    int sum = 0;
    set<int>::iterator it = item.begin(),it1,it2;
    for ( ; it!= item.end() ; it++ )
    {
        sum += (*it)*(*it)%M;
        sum %= M;
    }
    for ( int i = 0 ; i < hash[sum].size() ; i++ )
    {
        int x = hash[sum][i];
        set<int>& temp = I[x].elements;
        it = temp.begin();
        bool flag = true;
        if ( temp.size() != item.size() ) continue;
        for ( it1 = temp.begin() , it2 = item.begin(); it2!= item.end() ; it1++,it2++ )
            if ( *it1 != *it2 ) 
            {
                flag = false;
                break;
            }
        if ( flag ) return x;
    }
    return -1;
}

int  make_hash ( set<int>& item )
{
    int sum = 0;
    set<int>::iterator it = item.begin();
    for ( ; it!= item.end() ; it++ )
    {
        sum += (*it)*(*it)%M;
        sum %= M;
    }
    hash[sum].push_back ( cnts );
    return cnts++;
}

void add ( int u , int v , int x )
{
    edge[u].push_back ( v );
    val2[u].push_back ( x );
}

void dfs ( set<int>& elements , int u , int d , int flag )
{
    if ( vis[u][d] ) return;
    vis[u][d] = 1;
    if ( d == 1 ) elements.insert ( u );
    if ( d == 2 ) return;
    int len = e[u].size();
    for ( int i = 0 ; i < len ; i++ )
    {
        int v = e[u][i],dd;
        int x = val1[u][i];
        if ( x == flag ) dd = d+1;
        else if ( x == 0 ) dd = d;
        else continue;
        dfs ( elements , v , dd , flag );
    }
}

void ensure ( )
{
    I[0].elements.insert(start);
    cnts = 1;
    for ( int i = 0 ; i < cnts ; i++ )
    {
        set<int>& cur = I[i].elements;
        for ( int j = 0 ; j < types.size() ; j++ )
        {
            if ( types[j] == 0 ) continue;
            memset ( vis , 0 , sizeof ( vis ) );
            set<int>& temp = I[cnts].elements;
            temp.clear();
            set<int>::iterator it = cur.begin();
            for ( ; it != cur.end() ; it++ )
                dfs ( temp , *it , 0 , types[j] );
            if ( temp.empty() ) continue;
            int x = get_hash ( temp );
            if ( x == -1 ) 
                x = make_hash ( temp );
            add ( i , x , types[j] );
        }
        set<int>::iterator it = cur.begin();
        printf ( "I%d :" , i );
        for ( ; it!= cur.end() ; it++ )
            printf ( "%d " , *it );
        puts ("");       
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205

2. DFA的最小化

2.1. 明确DFA的定义

一个确定的有穷自动机(DFA)M是一个五元式:

  • M=(S, ∑, δ, s0, F)其中 
    • S是一个有限集,它的每个元素称为一个状态。
    • ∑是一个有穷字母表,它的每个元素称为一个输入字符 
      -δ是一个从S×∑至S的单值映射。δ(s,a)=s’意味着:当现行状态-为s、输入字符为a时,将转换到下一个状态s’。我们称s’为s的一个后继状态。
    • s0 ∈S,是唯一的初态。
    •  S,是一个终态集(可空)

2.2 算法描述

  • DFA M =(K,∑,f, k0,, kt),最小状态DFA M’ 
    • 1.构造状态的初始划分 0 :终态kt 和非终态K- kt两组
    • 2.对∏施用传播性原则 构造新划分 new
    • 3.如 new= ,则令 new= 并继续步骤4,否则 :=new 重复2
    • 4.为 final 中的每一组选一代表,这些代表构成M’的状态。若k是一代表且f(k,a)=t,令r是t组的代表,则M’中有一转换f’(k,a)=r M’ 的开始状态是含有K0的那组的代表 M’的终态是含有Kt的那组的代表
    • 5.去掉M’中的死状态.

2.3 代码实现

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <fstream>
#define MAX 507

using namespace std;

struct Node
{
    int x;
    int type;
    Node(){}
    Node( int a , int b )
        :x(a),type(b){}
    bool operator < ( const Node& a ) const
    {
        return type < a.type;
    }
};

int mp[MAX][MAX];
vector<int> _edge[MAX];
vector<int> _val[MAX];
vector<int> edge[MAX];
vector<int> val[MAX];
vector<int> point;
vector<pair<int,int> > ans1;
vector<int> ans2;
vector<Node> col;
int fa[MAX];
int type[MAX];
int state[MAX];
int used[MAX];
int kinds;
int groups_num;
int n;
int m;

void init ();
int _find( int x );
void _union ( int x , int y );
void _add ( int u , int v , int x );
void add ( int u , int v , int x );
void minimize ( );
void make_csv();

int main ( )
{
    init ( );
    scanf ( "%d%d" , &n , &m );
    for ( int i = 1 ; i <= n ; i++ )
        scanf ( "%d" , &type[i] );
    for ( int i = 0 ; i < m ; i++ )
    {
        int u,v,x;
        scanf ( "%d%d%d" , &u , &v , &x );
        _add ( u ,v , x );
    }
    minimize();
    //最小化后的点的保留结果
    puts ("points : " );
    printf ( "%d\n" , (int)point.size() );
    for ( int i = 0 ; i < point.size(); i++ )
        printf ( "%d " , point[i] );
    puts("");
    //最小化后的边的保留结果
    puts ( "edge: ");
    m = ans1.size();
    for ( int i = 0 ; i < ans1.size() ; i++ )
        printf ( "%d %d %d\n" , ans1[i].first , ans1[i].second , ans2[i] );
    puts("");
    make_csv();
}

void init ( )
{
    for ( int i = 0 ; i < MAX ; i++ )
    {
        edge[i].clear();
        _edge[i].clear();
    }
    point.clear();
    memset ( type , 255 , sizeof ( type ) );
    memset ( used , 0 , sizeof ( used ) );
    kinds = 0;
    groups_num = 2;
    col.clear();
    for ( int i = 0 ; i < MAX ; i++ )
        fa[i] = i;
}

void _add ( int u , int v , int x )
{
    _edge[u].push_back ( v );
    _val[u].push_back ( x );
    if ( used[x] ) return ;
    used[x] = x;
    kinds++;
}

void add ( int u , int v , int x )
{
    edge[u].push_back ( v );
    val[u].push_back ( x );
}

int _find ( int x )
{
    return x == fa[x]? x: fa[x] = _find ( fa[x] );
}

void _union ( int x , int y )
{
    x = _find ( x );
    y = _find ( y );
    fa[x] = y;
}

void minimize ( )
{
    queue<vector<Node> > q[2];
    col.clear();
    for ( int i = 1 ; i <= n ; i++ )
    {
        if ( type[i] == 0 ) 
            col.push_back ( Node( i , 0 ) );
    }
    q[1].push ( col );
    col.clear();
    for ( int i = 1 ; i <= n ;i++ )
    {
        if ( type[i] == 1 )
            col.push_back ( Node ( i , 1 ) );
    }
    q[1].push( col );
    col.clear();
    for ( int i = 1 ; i <= kinds ; i++ )
    {
        int cur = i%2;
        int next = (i+1)%2;
        while ( !q[next].empty() ) q[next].pop();
        while ( !q[cur].empty() )
        {
            vector<Node> front = q[cur].front();
            q[cur].pop();
            for ( int j = 0 ; j < front.size() ; j++ )
            {
                Node& temp = front[j];
                int u = temp.x;
                for ( int k = 0 ; k < _edge[u].size() ; k++ )
                {
                    int v = _edge[u][k];
                    int x = _val[u][k];
                    if ( x != i ) continue;
                    temp.type = type[v];
                }
            }
            sort ( front.begin() , front.end() );
            if ( front[0].type == front[front.size()-1].type )
                q[next].push ( front );
            else 
            {
                col.clear();
                col.push_back ( front[0] );
                for ( int j = 1 ; j < front.size() ; j++ )
                {
                    if ( front[j].type != front[j-1].type )
                    {
                        q[cur].push ( col );
                        col.clear();
                        groups_num++;
                    }
                    type[front[j].x] = groups_num;
                    col.push_back ( front[j] );
                }
                q[cur].push( col );
            }
        }
    }
//#define DEBUG
#ifdef DEBUG
    int id = (kinds+1)%2;
    int num = 1;
    while ( !q[id].empty() )
    {
        vector<Node> temp = q[id].front();
        q[id].pop();
        printf ( "%d : ",  num++ );
        for ( int i = 0 ; i < temp.size() ; i++ )
            printf ( "%d " , temp[i].x );
        puts("");
    }

#else
    int id = (kinds+1)%2;
    while ( !q[id].empty() )
    {
        vector<Node> temp = q[id].front();
        q[id].pop();
        for ( int i = 1 ; i < temp.size() ; i++ )
            _union ( temp[i].x , temp[i-1].x);
    }
    memset ( used , 0 , sizeof ( used ) );
    memset ( mp , 0 , sizeof ( mp ) );
    for ( int i = 1 ; i <= n ;i++ )
    {
        int x = _find(i);
        if ( used[x] ) continue;
        used[x] = 1;
        point.push_back ( x );
    }
    ans1.clear();
    for ( int i = 1 ; i <= n ; i++ )
        for ( int j = 0 ; j < _edge[i].size() ; j++ )
        {
            int v = _edge[i][j];
            int x = _val[i][j];
            int a = _find(i);
            int b = _find(v);
            if ( mp[a][b] ) continue;
            mp[a][b] = 1;
            add ( a , b , x );
            ans1.push_back ( make_pair ( a , b ) );
            ans2.push_back ( x );
        }
#endif
}

void make_csv ( )
{
    freopen ( "g1.csv" , "w" , stdout );
    printf ( "%d,%d, \n" , n , m  ); 
    for ( int i = 0 ; i < point.size() ; i++ )
        if ( i == 0 ) printf ( "%d" , point[i] );
        else printf ( ",%d" , point[i] );
    puts("");
    for ( int i = 0 ; i < m ; i++ )
        printf ( "%d,%d,%d\n" , ans1[i].first , ans1[i].second , ans2[i] );
    fclose(stdout);
}
  • 6
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
编译原理是学习计算机科学的一门基础课程,主要涉及语言的识别和转化,而正则表达式则是其中一个非常重要的工具。在编译原理中,正则表达式通常用于描述一些模式,比如关键字、标识符等。因此,掌握正则表达式的转换过程对于理解编译原理课程非常重要。 正则表达式的转换过程主要包括以下几个部分:正则表达式转NFANFADFADFA最小化。其中,NFA(非确定有限状态自动机)和DFA确定有限状态自动机)都是描述正则表达式的模型。 正则表达式转NFA: 首先,正则表达式中的基本元素是字符、括号和运算符。在转换为NFA的过程中,需要设计出一些状态来描述不同的字符和运算符。 对于字符来说,我们可以为它们设计出一个状态,状态的入口边是字符,出口边为空。 对于括号和运算符来说,可以为它们设计出一些连接状态。例如在括号中的字符可以通过连接状态直接连接到后面的状态,或者通过其他运算符先连接到其他的状态再连接到后面的状态。 最后,需要定义一个起始状态和一个终止状态,起始状态与第一个字符状态相连,最后一个字符状态与终止状态相连。这样,我们就得到了一张NFA图。 NFADFA: 将一个NFA图转换成DFA图的主要目的是为了简化图结构,以便后续对文本进行识别。 首先,需要定义DFA的状态集合,每个集合都对应一个状态。因为DFA是完全确定的有限状态自动机,所以在DFA中只能有一个状态。 然后,需要将NFA图中的每个状态都映射为DFA图中的一个状态,以便对文本进行识别。当NFA图中有多个状态对应于DFA图中的同一状态时,需要将它们合并,并将它们的出口边合并成一个出口边。 DFA最小化: 最后,对DFA进行最小化处理,以便减少状态数,提高运行效率。在最小化处理时需要考虑不同状态之间的等价关系。 可以采用遍历算法,将DFA中的状态按照等价关系划分为若干个等价类,然后构造一个等价类访问表,每个表项对应一个状态集。 最小化后的DFA图是可以识别文本的,可以用于在编译器中进行文本匹配和词法分析等操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值