表达式求值
总体思路
自左至右扫描表达式,若遇到操作数则压入操作数栈;遇到运算符,则需要比较其与运算符栈栈顶元素的优先级,若其优先级高于栈顶元素优先级则进栈,反之则取出栈顶运算符和操作数栈栈顶的连续两个操作数进行运算,并将结果存入操作数栈,然后继续比较该运算符与栈顶运算符的优先级。左括号压入运算符栈,右括号不压入运算符栈,取出运算符栈栈顶运算符和操作数栈栈顶的两个操作数进行运算,并将结果压入操作数栈,直到弹出左括号为止。
代码实现
初始化
此处需创建两个栈,一个栈用于存放操作数,另一个用于存放运算符,代码实现如下:
typedef struct numStack
{
int numTop;
int numData[MAXSIZE];
} numStack, *numStackPtr;
typedef struct charStack
{
int charTop;
char charData[MAXSIZE];
} charStack, *charStackPtr;
/* 数字栈初始化 */
numStackPtr initNumStack()
{
numStackPtr numHeader = (numStackPtr)malloc(sizeof(numStack));
numHeader->numTop = -1;
return numHeader;
}
/* 操作符栈初始化 */
charStackPtr initCharStack()
{
charStackPtr charHeader = (charStackPtr)malloc(sizeof(charStack));
charHeader->charTop = -1;
return charHeader;
}
操作数压栈及运算符压栈
-
自左至右扫描表达式,当遇到操作数时将其压入操作数栈
-
当遇到运算符时,若其优先级高于栈顶元素优先级则进栈
-
反之取出栈顶运算符和操作数栈栈顶的连续两个操作数进行运算,并将结果存入操作数栈,然后继续比较该运算符与栈顶运算符的优先级。
/* 数字压栈 */
void numPush(numStackPtr tempNumStack, int tempNum)
{
if(tempNumStack->numTop >= MAXSIZE - 1)
{
printf("无法压入元素%d:栈已满!\n",tempNum);
return;
}
tempNumStack->numTop++;
tempNumStack->numData[tempNumStack->numTop] = tempNum;
}
/* 操作符压栈 */
void charPush(charStackPtr tempCharStack, char tempChar)
{
if(tempCharStack->charTop >= MAXSIZE - 1)
{
printf("无法压入元素%c:栈已满!\n",tempChar);
return;
}
tempCharStack->charTop++;
tempCharStack->charData[tempCharStack->charTop] = tempChar;
}
操作数及运算符弹栈
此处较为简单,就不再赘述了
/* 数字弹栈 */
int numPop(numStackPtr tempNumStack)
{
if(tempNumStack->numTop == -1)
{
printf("无法弹出元素:栈为空!\n");
return NULL;
}
tempNumStack->numTop--;
return tempNumStack->numData[tempNumStack->numTop+1];
}
/* 操作符弹栈 */
char charPop(charStackPtr tempCharStack)
{
if(tempCharStack->charTop == -1)
{
printf("无法弹出元素:栈为空!\n");
return NULL;
}
tempCharStack->charTop--;
return tempCharStack->charData[tempCharStack->charTop+1];
}
判断优先级
*
和/
的优先级高于+
和-
,故在表达式中应与数学上先查出后加减的规则相同,此处设*
和/
的优先级数为2
,+
和-
的优先级数为1
,通过比较返回的优先级数的大小比较运算符的优先级。
int judgePriority(char tempChar)
{
if(tempChar == '+' || tempChar == '-')
{
return 1;
}else if(tempChar == '*' || tempChar == '/')
{
return 2;
}
}
计算(核心代码)
1. 由于输入表达式时,是将数字以字符形式存入字符串中,所以一个单元格只能存一位数字,在处理多位数时,采用归并的思想,先读取一位数字expression[j++]
,再设int tempResult = 0
,通过tempResult = tempResult * 10 +expression[j++] - '0'
实现将已读取到的数字归并到tempResult
中;以此往复,若下一位为数字则归并一次。
2. 读取时遇到运算符,则比较其与运算符栈栈顶元素的优先级,若其优先级低于栈顶元素优先级则进行计算,并将结果存入操作数栈,继续比较该运算符与栈顶运算符的优先级。遇到右括号时不将其压入运算符栈,取出运算符栈栈顶运算符和操作数栈栈顶的两个操作数进行运算,并将结果压入操作数栈,直到弹出左括号为止。
/* 计算 */
void eval(numStackPtr tempNumStack, charStackPtr tempCharStack)
{
int a = numPop(tempNumStack);
int b = numPop(tempNumStack);
char c = charPop(tempCharStack);
int tempResult;
switch (c)
{
case '+':
tempResult = b + a;
break;
case '-':
tempResult = b - a;
break;
case '*':
tempResult = b * a;
break;
case '/':
tempResult = b / a;
break;
default:
break;
}
numPush(tempNumStack,tempResult);
}
int main()
{
numStackPtr tempNumStack = initNumStack();
charStackPtr tempCharStack = initCharStack();
char expression[2*MAXSIZE];
gets(expression);
for(int i = 0;i < strlen(expression); ++i)
{
char temp = expression[i];
if(isdigit(temp))
{
int tempResult = 0,j = i;
while (j < strlen(expression) && isdigit(expression[j]))
{
tempResult = tempResult * 10 +expression[j++] - '0';
}
i = j - 1;
numPush(tempNumStack,tempResult);
}else if(temp == '(')
{
charPush(tempCharStack,temp);
}else if(temp == ')')
{
while (tempCharStack->charData[tempCharStack->charTop] != '(')
{
eval(tempNumStack,tempCharStack);
}
charPop(tempCharStack);
}else
{
while(tempCharStack->charTop != -1 && tempCharStack->charData[tempCharStack->charTop] != '(' && judgePriority(tempCharStack->charData[tempCharStack->charTop]) >= judgePriority(temp))
{
eval(tempNumStack,tempCharStack);
}
charPush(tempCharStack,temp);
}
}
while(tempCharStack->charTop != -1)
{
eval(tempNumStack,tempCharStack);
}
printf("%d\n",tempNumStack->numData[tempNumStack->numTop]);
return 0;
}
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXSIZE 40
typedef struct numStack
{
int numTop;
int numData[MAXSIZE];
} numStack, *numStackPtr;
typedef struct charStack
{
int charTop;
char charData[MAXSIZE];
} charStack, *charStackPtr;
/* 数字栈初始化 */
numStackPtr initNumStack()
{
numStackPtr numHeader = (numStackPtr)malloc(sizeof(numStack));
numHeader->numTop = -1;
return numHeader;
}
/* 操作符栈初始化 */
charStackPtr initCharStack()
{
charStackPtr charHeader = (charStackPtr)malloc(sizeof(charStack));
charHeader->charTop = -1;
return charHeader;
}
/* 数字压栈 */
void numPush(numStackPtr tempNumStack, int tempNum)
{
if(tempNumStack->numTop >= MAXSIZE - 1)
{
printf("无法压入元素%d:栈已满!\n",tempNum);
return;
}
tempNumStack->numTop++;
tempNumStack->numData[tempNumStack->numTop] = tempNum;
}
/* 操作符压栈 */
void charPush(charStackPtr tempCharStack, char tempChar)
{
if(tempCharStack->charTop >= MAXSIZE - 1)
{
printf("无法压入元素%c:栈已满!\n",tempChar);
return;
}
tempCharStack->charTop++;
tempCharStack->charData[tempCharStack->charTop] = tempChar;
}
/* 数字弹栈 */
int numPop(numStackPtr tempNumStack)
{
if(tempNumStack->numTop == -1)
{
printf("无法弹出元素:栈为空!\n");
return NULL;
}
tempNumStack->numTop--;
return tempNumStack->numData[tempNumStack->numTop+1];
}
/* 操作符弹栈 */
char charPop(charStackPtr tempCharStack)
{
if(tempCharStack->charTop == -1)
{
printf("无法弹出元素:栈为空!\n");
return NULL;
}
tempCharStack->charTop--;
return tempCharStack->charData[tempCharStack->charTop+1];
}
int judgePriority(char tempChar)
{
if(tempChar == '+' || tempChar == '-')
{
return 1;
}else if(tempChar == '*' || tempChar == '/')
{
return 2;
}
}
/* 计算 */
void eval(numStackPtr tempNumStack, charStackPtr tempCharStack)
{
int a = numPop(tempNumStack);
int b = numPop(tempNumStack);
char c = charPop(tempCharStack);
int tempResult;
switch (c)
{
case '+':
tempResult = b + a;
break;
case '-':
tempResult = b - a;
break;
case '*':
tempResult = b * a;
break;
case '/':
tempResult = b / a;
break;
default:
break;
}
numPush(tempNumStack,tempResult);
}
int main()
{
numStackPtr tempNumStack = initNumStack();
charStackPtr tempCharStack = initCharStack();
char expression[2*MAXSIZE];
gets(expression);
for(int i = 0;i < strlen(expression); ++i)
{
char temp = expression[i];
if(isdigit(temp))
{
int tempResult = 0,j = i;
while (j < strlen(expression) && isdigit(expression[j]))
{
tempResult = tempResult * 10 +expression[j++] - '0';
}
i = j - 1;
numPush(tempNumStack,tempResult);
}else if(temp == '(')
{
charPush(tempCharStack,temp);
}else if(temp == ')')
{
while (tempCharStack->charData[tempCharStack->charTop] != '(')
{
eval(tempNumStack,tempCharStack);
}
charPop(tempCharStack);
}else
{
while(tempCharStack->charTop != -1 && tempCharStack->charData[tempCharStack->charTop] != '(' && judgePriority(tempCharStack->charData[tempCharStack->charTop]) >= judgePriority(temp))
{
eval(tempNumStack,tempCharStack);
}
charPush(tempCharStack,temp);
}
}
while(tempCharStack->charTop != -1)
{
eval(tempNumStack,tempCharStack);
}
printf("%d\n",tempNumStack->numData[tempNumStack->numTop]);
return 0;
}
运行测试
4+4*2+4*(3+2)+(3+7)/5
4+4*2+4*(3+2)+(3+7)/5 = 34
c++版本
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <unordered_map>
using namespace std;
stack<int> num;
stack<char> op;
void eval()
{
auto b = num.top();
num.pop();
auto a = num.top();
num.pop();
auto c = op.top();
op.pop();
int x;
if (c == '+') x = a + b;
else if (c == '-') x = a - b;
else if (c == '*') x = a * b;
else x = a / b;
num.push(x);
}
int main()
{
unordered_map<char, int> pr{ {'+', 1}, {'-', 1}, {'*', 2}, {'/', 2} };
string str;
cin >> str;
for (int i = 0; i < str.size(); i++)
{
auto c = str[i];
if (isdigit(c))
{
int x = 0, j = i;
while (j < str.size() && isdigit(str[j]))
x = x * 10 + str[j++] - '0';
i = j - 1;
num.push(x);
}
else if (c == '(') op.push(c);
else if (c == ')')
{
while (op.top() != '(') eval();
op.pop();
}
else
{
while (op.size() && op.top() != '(' && pr[op.top()] >= pr[c]) eval();
op.push(c);
}
}
while (op.size()) eval();
cout << str <<" = "<< num.top() << endl;
return 0;
}
运行结果
4+4*2+4*(3+2)+(3+7)/5
4+4*2+4*(3+2)+(3+7)/5 = 34
注:该代码需在较高版本环境下才能运行