運算時求值核心思想:將運算式逐字符讀取,若是運算數就進運算數棧,若是運算符就與運算符棧頂比較運算符的優先級來做相應的操作。直到遇到運算式的結束符且運算符棧里沒有運算符為止。
因為用到了兩個棧(運算符棧和運算數棧)且這兩個棧的基本存儲類型還不一樣,一個為char類型存儲運算符,而另一個為float類型存儲數值的。所以就調用了兩個棧的頭文件Stack_Float.h和Stack_Char.h。兩個頭文件實現的基本操作是一樣的,只是里面的結構體類型進行了改動。如下:
1 /*Stack_Char.h*/ 2 typedef char CElemType; 3 typedef struct 4 { 5 CElemType data[MAXSIZE]; 6 int top; 7 }StackChar;
1 /*Stack_Float.h*/ 2 typedef float FElemType; 3 typedef struct 4 { 5 FElemType data[MAXSIZE]; 6 int top; 7 }StackFloat;
還有棧的基本操作函數GetTop函數進行了改動。為了方便之后函數功能的實現,將數值參數去掉了,為了省事也去掉了對棧是否為空的判斷,不管棧如何直接返回棧頂元素,容易出錯。其他的基本函數與之前寫的棧的順序實現一樣,記得將所有宏類型名稱替換。GetTop函數如下以char類型為例:
1 CElemType GetTop(StackChar S) 2 { 3 return S.data[S.top]; 4 }
核心代碼實現如下:
1 #include "Stack_Float.h" 2 #include "Stack_Char.h" 3 #include "string.h" 4 5 unsigned char Prior[7][7] = { 6 '>','>','<','<','<','>','>', 7 '>','>','<','<','<','>','>', 8 '>','>','>','>','<','>','>', 9 '>','>','>','>','<','>','>', 10 '<','<','<','<','<','=',' ', 11 '>','>','>','>',' ','>','>', 12 '<','<','<','<','<',' ','=' 13 }; //算符間的優先關系,對應的實現關系在代碼下面拋出 14 15 #define OPSETSIZE 7 16 char OPSET[OPSETSIZE]={'+' , '-' , '*' , '/' ,'(' , ')' , '#'}; //運算符集;運算符先支持+-*/,#為結束符 17 18 //返回a與b的運算結果 19 float Operate(float a, unsigned char theta, float b) 20 { 21 switch(theta) 22 { 23 case '+': 24 return a+b; 25 case '-': 26 return a-b; 27 case '*': 28 return a*b; 29 case '/': 30 return a/b; 31 default : 32 return 0; 33 } 34 } 35 36 //判斷Test字符是否在運算符集里 37 Status In(char Test, char* TestOp) 38 { 39 bool Find = false; 40 for (int i = 0; i< OPSETSIZE; i++) 41 { 42 if (Test == TestOp[i]) Find = true; 43 } 44 return Find; 45 } 46 47 //返回運算符在運算符集里的位置 48 int ReturnOpOrd(char op,char* TestOp) 49 { 50 int i; 51 for(i = 0; i < OPSETSIZE; i++) 52 { 53 if (op == TestOp[i]) return i; 54 } 55 return 0; 56 } 57 58 //返回兩個運算符的優先級 59 char precede(char Aop, char Bop) 60 { 61 return Prior[ReturnOpOrd(Aop,OPSET)][ReturnOpOrd(Bop,OPSET)]; 62 } 63 64 //求解運算式 65 float EvaluateExpression(char* MyExpression) 66 { 67 StackChar OPTR; // 運算符棧,字符元素 68 StackFloat OPND; // 運算數棧,實數元素 69 char TempData[20]; 70 float Data,a,b; 71 char theta,*c,x,Dr[2]; 72 /*初始化棧 73 /*運算符棧先進棧一個#結束符做開始*/ 74 InitStack (OPTR); 75 Push (OPTR, '#'); 76 InitStack (OPND); 77 c = MyExpression; //c指向求解的運算式 78 strcpy_s(TempData,"\0"); 79 while(*c != '#' || GetTop(OPTR) != '#')//結束條件指針c指向和運算符棧棧頂均為結束符# 80 { 81 if (!In(*c, OPSET)) //若是運算數則進運算數棧 82 { 83 Dr[0] = *c; 84 Dr[1] = '\0'; 85 strcat_s(TempData,Dr); 86 c++; 87 if(In(*c,OPSET)) 88 { 89 Data = (float)atof(TempData);//將char類型值轉換成float型數值 90 Push(OPND, Data); 91 strcpy_s(TempData,"\0"); 92 } 93 } 94 else //不是運算數則進運算符棧 95 { 96 switch (precede(GetTop(OPTR), *c)) 97 { 98 case '<': // 棧頂元素優先權低 99 Push(OPTR, *c); 100 c++; 101 break; 102 case '=': // 脫括號並接收下一字符 103 Pop(OPTR, x); 104 c++; 105 break; 106 case '>': // 退棧並將運算結果入棧 107 Pop(OPTR, theta); 108 Pop(OPND, b); 109 Pop(OPND, a); 110 Push(OPND, Operate(a, theta, b)); 111 break; 112 } 113 } 114 } 115 return GetTop(OPND); 116 }
其中Prior二維數組作用為判斷運算符優先級。實現表:
+ - * / ( ) #
+ > > < < < > >
- > > < < < > >
* >> > > < > >
/ > > > > < > >
( < < < < < =
) > > > > > >
# < < < < < =
對不齊咳咳咳 。
支持的運算有:+、-、*、/、();
測試數據直接printf輸出EvaluateExpression函數就行了,注意調用的參數是字符串且要以#結束符結尾。