計算理論101:這可能是講FSM的最生動的一篇了

liaochangjiang發表於2019-04-20

本文參考了:

簡介

這是《計算理論101》系列的第一篇,將從最基本的有限狀態機講起。主要參考的課程和書籍有: Introduction to the Theory of Computation 3rd Edition【Stonehill college CS】Introduction to the Theory of Computation

為什麼要學習『計算理論』?

計算理論101:這可能是講FSM的最生動的一篇了

如 Stonehill college 的 Professor of Computer Science Shai Simonson所說,這可能是計算機課程中最抽象的一門了,但卻是任何 computer scientist(我覺得可以延生至任何真正熱愛 CS 的人)至少需要了解的一門課。這門課不會教你如何寫程式碼,也不會教你如何做一個計算機,而是著重於『電腦科學』中的『科學』兩個字,去了解電腦科學發展幾十年來前人閃耀的思想。

還有一點,我認為也是很重要的,那就是學習新知識那份最單純的快樂。

計算理論101:這可能是講FSM的最生動的一篇了

好了,廢話不多說,開始正題~

什麼是有限狀態機

以一個程式設計師的角度,我的理解就是記憶體有限的一個機器,上面定義了一些函式,可以從一個狀態跳轉到另一個狀態。嚴格的數學定義,一個有限狀態機可以定義為一個五元組,如下圖表示(來源於Introduction to the Theory of Computation 3rd Edition P35):

計算理論101:這可能是講FSM的最生動的一篇了

可以用圖直觀地表示:下圖這個狀態機,圓圈表示的是可能出現的狀態,可能輸入的值為0和1,裝換函式就是那些箭頭,開始狀態為 q1,accept 狀態為 q2(用雙圓圈表示)。

計算理論101:這可能是講FSM的最生動的一篇了

一個有限狀態機的定義其實就是這麼簡單。

有限狀態機應用

有限狀態機一個最顯然的特點就是記憶體有限,無法記憶所有的歷史輸入,所以它能夠解決的問題是有限的。至於什麼問題能夠解決,什麼不能,後面再說。先來看看有限狀態機的應用。

嵌入式領域:自動門

這是《Introduction to the Theory of Computation 3rd Edition》書中提到的一個例子。

下圖中,門口和門背各有一個感應器(front 為門口,rear 為門背)。門的控制開關一共有兩個狀態:OPEN 和 CLOSED,輸入一共有四種情況:FRONT(門口有人)、REAR(門背有人)、BOTH(門口門背都有人)、NEITHER(兩邊都沒人)。

計算理論101:這可能是講FSM的最生動的一篇了

有一個圖表示狀態轉換過程為:

計算理論101:這可能是講FSM的最生動的一篇了

計算理論101:這可能是講FSM的最生動的一篇了

稍微解釋一下:

  • 處於 CLOSED 狀態,只有前面的 pad 檢測到有人時才會開啟,從 CLOSED 狀態變為 OPEN 狀態,其餘情況下維持狀態不變。
  • 處於 OPEN 狀態時,只有當兩邊都沒有檢測到人時,才轉換為 CLOSED 狀態。

我對於這個門的設計表示懷疑,處於 CLOSED 狀態時,難道 REAR PAD 檢測到人不應該變成 OPEN 狀態嗎?也許是我哪裡理解得不對,有童鞋知道的歡迎指出。不過這一點不影響我們對於有限自動機的理解。

這個自動門其實就可以看作是一個最簡單的計算機了,它只有一個 bit 的儲存空間,可以記錄當前門的狀態是OPEN 還是 CLOSED。類似的還有電梯, 飲料機 等等。

事實上,最開始我們骨灰級的程式設計師(電腦科學家)們,面對的就是類似的情況,儲存空間極其有限。現在的很多嵌入式裝置,記憶體同樣非常有限,所以有限狀態機還是有用武之地的。

程式設計領域:正規表示式

這裡推薦一個網站: regexper.com/ ,能夠非常直觀地將正規表示式還原為一個 finite state machine。另外開源地址如下: gitlab.com/javallone/r…

舉幾個正規表示式例子:

匹配手機號:/^1(3|4|5|7|8)\d{9}$/

計算理論101:這可能是講FSM的最生動的一篇了

匹配郵箱:^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$

計算理論101:這可能是講FSM的最生動的一篇了

匹配 IP 地址:^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$

計算理論101:這可能是講FSM的最生動的一篇了

這裡不深入程式碼層,不然這篇文章就講不完了。有興趣的童鞋自己 Google 一下,後面有機會可能會再次講到。

其他

這個 stackexchange 的連結裡面提到了很多: softwareengineering.stackexchange.com/questions/4…

設計有限狀態機

例項一

設計一個FSM,能夠識別被3整除的二進位制字串。比如accept 1001,reject 1101。 首先,我們可以把所有餘數(reminder)的可能性當作狀態,也就是三個狀態:0,1,2,其中0時 accept 狀態。 然後分析一下狀態轉換是怎麼樣的?二進位制數,末位新增一個0表示乘以2,末位加1表示乘以2再加1,對於餘數,同樣是乘2或者乘2加1,只不過餘數會『進位』。

  • 從起始狀態開始:最開始沒有輸入,也就是0。
  • 對於狀態0:輸入為0時維持不變,為1會跳轉到1。

計算理論101:這可能是講FSM的最生動的一篇了

  • 對於狀態1,輸入為0時,餘數要乘以2,變成了2;輸入為1時,餘數乘2加1,結果變為0(3)。

計算理論101:這可能是講FSM的最生動的一篇了

  • 對於狀態2:輸入0乘以2,變為1(4);輸入1乘以2再加一,變為2(5)。

計算理論101:這可能是講FSM的最生動的一篇了

這樣就做完了,一個用普通演算法很難解決的問題,用FSM是不是很簡單?會設計識別能被3整除的 FSM,接下來被4、5、6、7、8整除的是不是也會了?這裡,被2^k(k=1,2,3,4)整除還有一個更簡單的方法:轉換為判斷末位至少有k 個0

動手來畫一畫:

例項二

設計一個 FSM,能夠識別 能被4整除的二進位制字串(末尾至少有兩個0)。 這裡把狀態設計為目前為止末尾收到了幾個0,一共有三個狀態:0個0,1個0,2個0。

計算理論101:這可能是講FSM的最生動的一篇了

有這個還可以推廣到模式字串識別,比如要識別特定子字串 ,請看下面這個例子。

例項三

設計一個 FSM,能夠識別子字串abcab

為了簡單起見,這裡把圓圈省略掉了,同時把中間的某些節點的狀態轉換忽略掉了。

  • 最開始,狀態為未匹配任意字元。
  • 在起始狀態:輸入 a,跳轉到 a;輸入其他狀態保持不變。
  • 在狀態 a:輸入 b 跳轉到 ab;輸入 a 維持狀態不變;輸入其他跳回起始狀態。
  • 在狀態 abc:輸入 a 跳轉到 abca;否則跳回起始狀態。
  • 在狀態 abca:輸入 b 跳轉到 abcab,也就是accept 狀態;輸入 a 跳轉回 a(注意不是跳轉回起始狀態,因為現在是 abcaa,也就相等於 a);輸入其他跳轉回起始狀態。
  • 在狀態 abcab:無論輸入什麼,都維持不變,因為當前已經匹配成功了。

計算理論101:這可能是講FSM的最生動的一篇了

總結一下

狀態機的定義非常簡潔,但是功能很強大,而且非常有意思不是嗎?

碼字很辛苦,圖文並茂更辛苦,點個贊鼓勵一下~

計算理論101:這可能是講FSM的最生動的一篇了

計算理論101:這可能是講FSM的最生動的一篇了

廣告時間,歡迎大家關注我的微信公眾號。同時本文同步於 github: github.com/liaochangji…

計算理論101:這可能是講FSM的最生動的一篇了

相關文章