數據結構-棧的實現之運算式求值


運算時求值核心思想:將運算式逐字符讀取,若是運算數就進運算數棧,若是運算符就與運算符棧頂比較運算符的優先級來做相應的操作。直到遇到運算式的結束符且運算符棧里沒有運算符為止。

因為用到了兩個棧(運算符棧和運算數棧)且這兩個棧的基本存儲類型還不一樣,一個為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函數就行了,注意調用的參數是字符串且要以#結束符結尾。

 


免責聲明!

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



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