C 實現對數學基本運算表示式的解析

2021-08-15 21:16:37 字數 3045 閱讀 9406

**位址如下:

前段時間在leetcode上刷題,遇到了很多涉及對字串進行解析的題目。可能是出於這個原因,最近迷戀上了字串的解析問題。數學基本運算表示式的解析就涉及這類問題。所謂數學基本運算表示式的解析就是指給定乙個表示式字串,如1 + 1,3 * 9,對這個字串進行解析,從而得到這個表示式的運算結果。(數學基本運算表示式也就是只用加減乘除進行計算的數學表示式)

其實站在我的角度來看,我覺得對數學基本運算表示式的解析還是有一定難度的。因為如果一開始沒有正確的思路,我們是很難找到這個問題的著手點的,畢竟解析數學基本運算表示式需要考慮到的問題是有點多的,以下,我把其中主要的問題列舉出來:

這些問題如果得不到恰當的處理,就會使解析過程失敗。

在實現解析數學基本運算表示式之前,我們首先得弄清楚哪些表示式是合法的,哪些表示式是不合法的。以下我將列舉c/c++等語言中,一些合法與不合法的表示式:

/* 合法 */

7 + 22 + 7 * 27

6 + -13 * 23 / -30 / 35

24 - +34

10 + (3 * 9) / 8

/* 不合法 */

abc + 123

// abc不是數字

1 + 2 * // *後缺少數字

6 + + 12

// 不能連用加號

8 - - 17

// 不能連用減號

32 + () - 4

// 括號中沒有內容

(0 + 5)) * 7

// 右括號多了乙個

((11 + 9) / 2

// 左括號多了乙個

不排除有一些程式語言支援上述所說的部分或者全部不合法表示式,但這裡我們先使用c/c++標準。

(可能網上有大佬提供了更好、更高效的解析數學表示式方法,不過我認為我的處理方式是非常直白易懂的一種。)

首先,我們來回憶一下我們做數學計算時的情形:

第一步

如果數**算表示式存在括號的話,我們會率先找到括號裡的內容,並將括號裡的內容當作乙個新的數學表示式進行優先運算。將這個新的數學表示式進行運算後,用得到的結果將括號及括號間的內容替換掉。當我們把所有括號裡的內容都用相應的結果替換掉後,就能得到原先數學表示式消去括號後的簡化式子,然後我們再對這個式子進行處理。例如原有的數學式7 * (5 + 3),進行消去括號的處理後,就得到了7 * 8,接下來我們再對這個式子進行解析和計算,就能得到答案。

第二步

消去括號的數學基本運算表示式就只剩加減乘除符號以及數字、小數點(如果有小數的話)了。由於乘法和除法要優先運算,如果式子中有這兩種運算的話,我們就要率先在式子中進行乘法運算和除法運算。運算的過程中,我們採用的做法同樣是把運算得到的結果替換掉原來的表示式子。如下計算過程示例可能會讓你重拾這一過程:

7 + 18 * 5 / 9

| v

7 + 90 / 9

| v

7 + 10

第三步進行完前兩步的處理,剩下的式子就只有加減符號以及數字、小數點(如果有小數的話)了。用和第二步中類似的做法進行計算,最後,式子就化成了數字,這個數字就是我們的答案。以第二步示例中最後得到的式子為例,7 + 10運算得到17,17就是最後的答案。

現在,我們回憶完了平日裡我們進行數學計算的步驟,其實這就是乙個對表示式逐漸化簡的過程。接下來我們就要從這些步驟中構思我們的解析演算法。

在第一步中,我們提到了對括號裡的內容進行優先計算。但是我們可能會遇到括號套括號的問題。但是正如第一步中所說,我們可以把括號裡的式子當作新的乙個式子來處理,對於新的式子又可以採用第一步到第三步的方式依次進行處理得到結果,其中的第一步又可以對新式子中的子括號進行處理。這樣一來就形成了一種遞迴關係。所以,我們只用實現如下幾個介面,就能完成對數學基本表示式的解析:

第一步用介面b來完成,第

二、三步用介面c來完成。介面c中使用介面d來進行結果運算,即介面c進行的操作是找到運算子並獲取運算子兩邊的數字,然後交給介面d對這兩個數字按照找到的運算子進行計算,再將得到的計算結果替換掉式子中相應的部分。而介面e為前幾個介面提供輔助功能。

介面a是呼叫其他介面的乙個入口。介面a~d的偽**如下:

/**

* 介面a

* @param exp 需要解析的表示式

*/float getvalue(const

string& exp)

/** * 介面b

* @param exp 需要解析的表示式

*/void handlebrackets(string& exp)

}}/**

* 介面c

* @param exp 需要解析的表示式

* @param operators 需要處理的運算符號(乘除一組,加減一組)

*/void handleoperator(string& exp, pair operators)

}}/**

* 介面d

* @param s1 用於計算的數字1

* @param _operator 運算子

* @param s2 用於計算的數字2

*/void basiccalc(const

string& s1, const

string& _operator, const

string& s2)

(至於介面e,由於是乙個提供輔助功能的介面集,所以上面的偽**中沒有給出。具體實現方法請參考給出的源**)

上面的偽**還只是乙個骨架,沒有血肉,還不能解決一些實際的問題(比如前文提到的如何處理括號,如何解決數字前的正負號等問題)。大家可以參考我給出的完整實現**。

當然,各位讀者也可以根據我前面的原理講解自行實現演算法。c++實現對數學基本運算表示式的解析

**位址如下:

C 運算表示式求值順序

優先順序雖然規定了運算物件的組合方式,但是沒有說明運算物件按照什麼順序求值。例如 int i f1 f2 我們不知道先求f1還是先求f2,倘若f1和f2指向並修改了同一物件,則會引發錯誤。例如 int i 0 cout 結果 本人在vs2017中得到的允許結果為1 1,這個就是錯誤表示式,產生未定義...

C 實現四則運算表示式的計算

輸入為乙個整數四則運算表示式,可以有括號。程式實現 這裡使用自己實現的棧類輔助操作 如下 include include include using namespace std 全域性變數 int priority tab 6 6 string operators 函式和類宣告 template c...

棧 四則運算表示式實現

棧的乙個常見應用,四則運算表示式求值。主要有兩個步驟 1,中綴轉字尾 2,字尾求值 實現起來比較簡單,我通過c 的容器stack實現一遍。從左到右遍歷中綴表示式的每個數字和符號,若是數字就輸出,即稱為字尾表示式的一部分,若是符號,則判斷其與棧頂符號的優先順序,是右括號或優先順序低於棧頂符號 乘除優先...