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

本文參考了:java

簡介

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

爲何要學習『計算理論』?

如 Stonehill college 的 Professor of Computer Science Shai Simonson所說,這多是計算機課程中最抽象的一門了,但倒是任何 computer scientist(我以爲能夠延生至任何真正熱愛 CS 的人)至少須要瞭解的一門課。這門課不會教你如何寫代碼,也不會教你如何作一個計算機,而是着重於『計算機科學』中的『科學』兩個字,去了解計算機科學發展幾十年來前人閃耀的思想。程序員

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

好了,廢話很少說,開始正題~正則表達式

什麼是有限狀態機

以一個程序員的角度,個人理解就是內存有限的一個機器,上面定義了一些函數,能夠從一個狀態跳轉到另外一個狀態。嚴格的數學定義,一個有限狀態機能夠定義爲一個五元組,以下圖表示(來源於Introduction to the Theory of Computation 3rd Edition P35):算法

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

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

有限狀態機應用

有限狀態機一個最顯然的特色就是內存有限,沒法記憶全部的歷史輸入,因此它可以解決的問題是有限的。至於什麼問題可以解決,什麼不能,後面再說。先來看看有限狀態機的應用。函數

嵌入式領域:自動門

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

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

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

稍微解釋一下:

  • 處於 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}$/

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

匹配 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]?)$

這裏不深刻代碼層,否則這篇文章就講不完了。有興趣的童鞋本身 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。

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

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

這樣就作完了,一個用普通算法很難解決的問題,用FSM是否是很簡單?會設計識別能被3整除的 FSM,接下來被四、五、六、七、8整除的是否是也會了?這裏,被2^k(k=1,2,3,4)整除還有一個更簡單的方法:轉換爲判斷末位至少有k 個0

動手來畫一畫:

實例二

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

有這個還能夠推廣到模式字符串識別,好比要識別特定子字符串 ,請看下面這個例子。

實例三

設計一個 FSM,可以識別子字符串abcab

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

  • 最開始,狀態爲未匹配任意字符。
  • 在起始狀態:輸入 a,跳轉到 a;輸入其餘狀態保持不變。
  • 在狀態 a:輸入 b 跳轉到 ab;輸入 a 維持狀態不變;輸入其餘跳回起始狀態。
  • 在狀態 abc:輸入 a 跳轉到 abca;不然跳回起始狀態。
  • 在狀態 abca:輸入 b 跳轉到 abcab,也就是accept 狀態;輸入 a 跳轉回 a(注意不是跳轉回起始狀態,由於如今是 abcaa,也就相等於 a);輸入其餘跳轉回起始狀態。
  • 在狀態 abcab:不管輸入什麼,都維持不變,由於當前已經匹配成功了。

總結一下

狀態機的定義很是簡潔,可是功能很強大,並且很是有意思不是嗎?

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

廣告時間,歡迎你們關注個人微信公衆號。同時本文同步於 github: github.com/liaochangji…

相關文章
相關標籤/搜索