数据结构-栈的实现之运算式求值
运算时求值核心思想:将运算式逐字符读取,若是运算数就进运算数栈,若是运算符就与运算符栈顶比较运算符的优先级来做相应的操作。直到遇到运算式的结束符且运算符栈里没有运算符为止。
因为用到了两个栈(运算符栈和运算数栈)且这两个栈的基本存储类型还不一样,一个为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函数就行了,注意调用的参数是字符串且要以#结束符结尾。