表示式求值之遞迴下降
阿新 • • 發佈:2019-01-29
本文旨在討論使用遞迴下降技術計算只含實數、+、-、*、/和()的數學表示式的值的問題,我只是一名大二的學生,為完成資料結構作業而研究該技術,所以瞭解的很膚淺,歡迎評論。
我們可以使用一種遞迴的方式來定義數學表示式,首先我寫出對一個數學表示式Expression的的遞迴定義形式:
Expression = Term + Expression | Term - Expression | Term
Term = Factor * Term | Factor / Term | Factor
Factor = (Expression) | 實數
我解釋下,每行代表一種表示式的生成規則,中間的豎線“|”意思是或。如:Factor = (Expression) | 實數,意思是一個Factor可以是被括號括起來的一個表示式,或者一個實數。這種定義形式利用的遞迴的思想。
下面,注意到每個表示式中都會有遞迴,但注意到每種表示式的生成規則中,運算子都是同級的,所以遞迴可以用迭代消除:
Expression = Term +或- Term +或- Term …… …… …… +或- Term
Term = Factor *或/ Factor *或/ Factor …… …… …… *或/ Factor
Factor = (Expression) | 實數
下面的我直接在程式碼的註釋中如何用程式碼實現。
#include <stdio.h> #include <stdlib.h> const int MAXN = 10000; char inputString[MAXN+1]; //輸入的表示式 int stringIndex = 0; //全域性變數,代表掃描到的位置 //函式宣告,每個函式名對應用於計算遞迴定義中的一項 double Expression(); double Term(); double Factor(); double Expression() { double numberA,numberB; numberA = Term(); //迭代求Term +或- Term +或- Term …… …… …… +或- Term while (inputString[stringIndex] == '+' || inputString[stringIndex] == '-') { char op = inputString[stringIndex++]; //運算子 numberB = Term(); //看吧、呼叫Term了 switch (op) { case '+': numberA += numberB; break; case '-': numberA -= numberB; break; default: break; } } if (inputString[stringIndex] == ')') //對應計算Factor = (Expression)時被呼叫,吃掉) stringIndex++; return numberA; } double Term() { double numberA,numberB; numberA = Factor(); while (inputString[stringIndex] == '*' || inputString[stringIndex] == '/') { char op = inputString[stringIndex++]; numberB = Factor(); //呼叫Factor switch (op) { case '*': numberA *= numberB; break; case '/': numberA /= numberB; break; default: break; } } return numberA; } double Factor() { if(inputString[stringIndex] == '(') //遇到(,由Factor = (Expression),吃掉左括號並計算括號中的Expression { stringIndex++; return Expression(); } else //否則直接掃描實數,關於strtod的用法請自己查證百度百科 { char *endptr; double numberA = strtod(inputString+stringIndex,&endptr); stringIndex = endptr-inputString; //這一步用於在strtod函式讀取完實數後,將stringIndex調至實數結尾的下一個位置 return numberA; } } int main() { for(;;) { scanf("%s",inputString); if(isalpha(*inputString)) break; stringIndex = 0; printf("=%lf\n",Expression()); } return 0; }
這個方法比課本上講的棧更簡潔,程式結構化更強,而且很好理解啊。
歡迎大家評論糾正以及補充。