NFA轉換為DFA


五一之后就開始實習了,接觸的第一件事就是解析正則,於是開始學習正則轉DFA的知識。看了很多帖子,始終在狀態move中的解析一帶而過,最終在網易雲課堂的一門課中找到答案。http://study.163.com/course/courseMain.htm?courseId=1002830012。我從中摘抄部分內容如下,如果覺得有用請去雲課堂里繼續學習。非常感謝這位老師。

摘抄:

大家好,歡迎大家來到coding迪斯尼,上一節我們研究了如何使用NFA識別輸入字符串,同時提出了來個概念,一個是ε閉包操作,一個是move得到轉移集合。這兩個操作在我們今天的主題,將NFA轉換為DFA的算法中將占據主導地位。我們任然以上一節用到的NFA狀態機為例子,看看它是怎么轉換為DFA的

 

NFA轉DFA算法:

我們先獲取NFA的起始節點,然后計算它的ε閉包:

ε-closure({17}) = { 17, 3 , 1, 4, 5, 9}

我們知道,處於ε閉包中的任何一個狀態節點時,我們可以不用輸入任何字符就可以直達其他節點,因此,閉包中的所有節點其實可以等價於一個節點,這個節點就可以作為NFA對應的DFA中的一個節點。因此我們把集合{ 17, 3 , 1, 4, 5, 9}

對應於一個節點,記為S0:

(S0, { 17, 3 , 1, 4, 5, 9})

於此同時把上面的節點標記加入一個隊列中,最為隊列的開頭:

[(S0, { 17, 3 , 1, 4, 5, 9})]

NFA狀態機可接受的字符是數字字符和字符 ’.’ ,接下來我們計算S0對數字字符和字符’.’ 的轉移集合:

Move(S0, .) = Move({ 17, 3 , 1, 4, 5, 9},  . ) = {6}

接着計算{6}的ε閉包:

ε-closure({6}) = {6,7},  然后看看{6,7}在上面的隊列中是否存在,由於當前隊列只有一個元素:[(S0, { 17, 3 , 1, 4, 5, 9})], 所以{6,7}在隊列中不存在,於是我們把{6,7}當做DFA的第二個狀態節點記做(S1, {6,7}), 把它加入到隊列中:

[(S0, { 17, 3 , 1, 4, 5, 9})]->[(S1, {6,7})]

這樣我們就有了兩個節點的對應關系 S0-(.)->S1.

我們再計算S0對應數字字符時所得的轉移集合:

Move(S0, D) = Move({ 17, 3 , 1, 4, 5, 9}, D) = {2, 10}

然后對{2,10}做閉包操作:

ε-closure({2,10}) = {2,10,4,5,1,11}

看看隊列中是否有{2,10,4,5,1,11}對應的節點,由於沒有對應節點,所以該集合可作為DFA的一個節點,記做(S2, {2,10,4,5,1,11}). 然后把它加入隊列:

[(S0, { 17, 3 , 1, 4, 5, 9})]->[(S1, {6,7})]->[(S2, {2,10,4,5,1,11})]

於是我們又有了一個節點對應關系:

S0-(D)->S2

最后我們得到DFA的三節點關系圖:

大家要注意,從圖上看S0 到 S2 只有一條邊,但是D代表的是數字字符的集合[0-9],所以實際上S0到S2有10條邊,也就是S0有10條出去的邊,邊對應的字符分別是0,1,2…9, 這十條邊都指向S2,上圖為了簡明,所以把這十條邊抽象為1條邊,在后續我們代碼中,構造的DFA將會有10條邊指向S2,這個差別大家要留心。

接下來我們計算S1對應數字字符和字符’.’所得到的轉移集合:

Move(S1, .) = Move({6,7}, .) = NULL

由於轉移集合是空,因此我們不做考慮,再看S1對應D的轉移集合

Move(S1, D) = Move({6,7}, D) = {8}

ε-closure({8}) = {8,18}.

在隊列中看看有沒有{8.18}對應的節點,由於沒有所以{8,18}可作為DFA新的節點,記為(S3, {8,18}),並加入隊列:

[(S0, { 17, 3 , 1, 4, 5, 9})]->[(S1, {6,7})]->[(S2, {2,10,4,5,1,11})]->[(S3, {8,18})]

同時意味着節點S1與節點S3有對應關系: S1-(D)->S3, 特別需要注意的是,S3的NFA節點集合中包含了NFA的終結節點18,所以S3是一個具有接受狀態的節點,於是我們得到DFA如下:

接下來我們計算S2的對應數字字符和字符’.’的轉移集合:

Move(S2, .) = Move({2,10,4,5,1,11}, .) = {6,12}

ε-closure({6,12}) = {6,12,7,15,13,16,18}

查看隊列看看有沒有上面閉包集合對應的點,由於沒有,所以上面閉包可以對應一個新的DFA節點,記為 (S4, {6,12,7,15,13,16,18})由於閉包集合含有NFA接受節點18, 所以S4是一個接受節點,把S4加入隊列:

[(S0, { 17, 3 , 1, 4, 5, 9})]->[(S1, {6,7})]->[(S2, {2,10,4,5,1,11})]->[(S3, {8,18})]->

[(S4, {6,12,7,15,13,16,18})]

同時我們得到對應關系 S2-(.)->S4

我們計算S2對應D的轉移集合:

Move(S2, D) = Move({2,10,4,5,1,11}, D) = {2}

ε-closure({2}) = {2, 1, 4, 5}

檢測一下閉包集合是否在隊列中,由於不在,所以它可以對應於DFA一個新節點記為 (S5, {2,1,4,5}), 把它加入隊列:

[(S0, { 17, 3 , 1, 4, 5, 9})]->[(S1, {6,7})]->[(S2, {2,10,4,5,1,11})]->[(S3, {8,18})]->

[(S4, {6,12,7,15,13,16,18})]->[(S5, {2,1,4,5})]

我們又得到一個對應關系S2-(D)->S5,這樣DFA狀態圖又更新為:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM