小學生都能看懂的表達式計算(圖解)


基礎知識


會加減乘除(納尼,這個還有不會的嗎

會雙向鏈表和樹(納尼,還個還要會嗎


溫故知新


表達式 2 + 3 - 4 + 5,人類計算的過程是這樣的,如下圖:

因為加減操作符優先級相同,所以從左到右依次運算。


可計算機不會這樣啊,必須先轉化為一棵樹(AST,抽象語法樹,這是編譯原理中的概念)才行,如下圖:

操作符上提變為根節點,左右操作數下降變為葉子節點,它們整體又成了一個操作數。依次對每個操作符使用這個規則,表達式即可變成一棵樹。


再接再厲


表達式 2 + 3 × 4 - 5 ÷ 6,人類的計算過程是這樣的,如下圖:

按照優先級從高到低,先乘除,再加減。


要想讓計算機來算啊,還得先轉換為一棵AST才行,如下圖:


發現問題


綜上,不難發現,先要把一個表達式轉化為一棵AST。人類根據操作符的優先級很自然地把一個表達式轉化為一棵樹,但是計算機該怎么做呢?


模仿人類


人類的視線可以在表達式上隨意掃描,對於不復雜的,一眼就發現優先級高的操作符,瞬間拿到它兩邊的操作數,就可以進行轉化了。


計算機在方式上無法和人類相比,但是在結果上必須要相同,即也要找到優先級高的操作符,也要知道它兩邊的操作數,然后再進行轉化。


回歸程序


定義一下操作符的優先級,優先級的數值沒有要求,如下圖:


當我們拿到一個操作符時,也要能拿到它左右兩邊的操作數,因操作符和操作數是間隔互聯的,實際它們就是一個雙向鏈表。


因我們要找出優先級高的操作符,所以必須先找出所有的操作符,然后再判斷優先級的高低。


把整個表達式里的操作數和操作符用雙向鏈表串起來,並把所有的操作符放入一個列表里。如下圖:


按優先級從高到低對操作符列表排序,優先級高的前移,優先級低的后移,優先級相同的相對位置不變。如下圖:


取出排在第一位的×,去雙向鏈表里找出它的左右操作數3和4,把這三個節點轉化為一棵樹,再把該樹作為操作數替換掉原來的三個節點,同時修復好與前面 + 號和后面 - 號的雙向鏈接。如下圖:


取出第二位的÷,采用和上面相同的方式進行轉化。如下圖:


取出第三位的+,采用相同的方式轉化。如下圖:


取出最后一位的-,采用相同的方式轉化后,整個表達式轉化完畢,變為一棵AST。如下圖:


推而廣之


操作符有了優先級之后,就限制了表達式的計算順序,人們有時希望打破這種限制,就引入了更神奇的操作符,就是小括號啦(哈哈)。


表達式 ( 2 + 3 ) × ( ( 4 - 5 ) ÷ 6 ),如果還想采用上面的套路,那么核心問題就落到了操作符的優先級上了。即如何真實地反映每個操作符的優先級值。


此時我們意識到,操作符的優先級不再是固定的,而是會隨着有沒有括號以及括號的嵌套深度而變化。其實小括號本來就是改變了操作符的優先級嘛,我們人類明白這一點,關鍵也要讓計算機明白。


既然括號是操作符,那也為它定義一個優先級值,這個值最好稍微大一些。如下圖:


定義一個上下文的基礎優先級值,默認當然是0了。


當遇到左括號時,基礎優先級值加上括號優先級值,相當於基礎優先級值得到了提升,這樣括號里的操作符因為有基礎優先級值的存在,所以自然抬高了自己的優先級值(相等於站到了巨人的肩膀上)。


當遇到右括號時,基礎優先級值減去括號優先級值,相當於此時新的基礎優先級值降到了進入括號前的水准。如下圖:


解析表達式,同時計算出每個操作符的優先級值(牢記,遇到一個左括號加100,遇到一個右括號減100)。如下圖:


按照實際優先級值從高到低排序操作符列表。如下圖:


最后按照相同的方式,轉換為一棵AST。如下圖:


后記:人類社會存在的歷史要比計算機的歷史長的多,從人類社會尋找問題的解決思路有時也是一個不錯的方向。甚至可以從大自然中尋找。



(完)


編程新說


用獨特的視角說技術

 


免責聲明!

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



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