1 中缀表达式
中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间。中缀表达式是人们常用的算术表示方法。
虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。对计算机来说,计算前缀或后缀表达式的值非常简单。
举例:
(3 + 4) × 5 - 6 就是中缀表达式
3 4 + 5 × 6 - 后缀表达式
2 后缀表达式
不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 , 即2 1 + 3 *
3 中缀表达式转后缀表达式
中缀转后缀的算法
遍历表达式中的数字和符号
对于数字:直接输出
对于符号:
左括号:进栈
运算符号:与栈顶元素进行优先级比较
若栈顶符号优先级低:此符号进栈(默认:栈顶若是左括号,左括号优先级最低)
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出
遍历结束:将栈中所有符号弹出并输出
中缀转后缀
代码实现:其中LinkStack.h的内容参考《数据结构之线性表——栈的链式存储》
#include"LinkStack.h"
#include<stdio.h>
using namespace std;
/*中缀转后缀的算法
遍历表达式中的数字和符号
对于数字:直接输出
对于符号:
左括号:进栈
运算符号:与栈顶元素进行优先级比较
若栈顶符号优先级低:此符号进栈(默认:栈顶若是左括号,左括号优先级最低)
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出
遍历结束:将栈中所有符号弹出并输出
中缀转后缀
*/
/*计算表达式结果:
*/
int isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}
int isLeft(char c)
{
return (c == '(');
}
int isRight(char c)
{
return (c == ')');
}
int priority(char c)
{
int ret = 0;
if ((c == '+') || (c == '-'))
{
ret = 1;
}
if ((c == '*') || (c == '/'))
{
ret = 2;
}
return ret;
}
void output(char c)
{
if (c != '\0')
{
printf("%c ", c);
}
}
void transform(const char* exp)
{
int i = 0;
LinkStack* stack = LinkStack_Create();
while (exp[i] != '\0')
{
if (isNumber(exp[i]))
{
output(exp[i]);
}
else if (isOperator(exp[i]))
{
while (LinkStack_Size(stack) > 0 && priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if (isLeft(exp[i]))
{
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if (isRight(exp[i]))
{
//char c = '\0';
while (!isLeft((char)(int)LinkStack_Top(stack)))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
while ((LinkStack_Size(stack) > 0) && (exp[i] == '\0'))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Destroy(stack);
}
int main()
{
transform("8+(3-1)*5");
printf("\n");
return 0;
}
4 后缀表达式的计算
遍历后缀表达式中的数字和符号
对于数字:进栈
对于符号:
从栈中弹出右操作数
从栈中弹出左操作数
根据符号进行运算
将运算结果压入栈中
遍历结束:栈中的唯一数字为计算结果
代码实现:其中LinkStack.h的内容参考《数据结构之线性表——栈的链式存储》
#include"LinkStack.h"
#include<stdio.h>
int isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}
int value(char c)
{
return (c - '0');
}
int express(int left, int right, char op)
{
int ret = 0;
switch (op)
{
case '+':
ret = left + right;
break;
case '-':
ret = left - right;
break;
case '*':
ret = left * right;
break;
case '/':
ret = left / right;
break;
default:
break;
}
return ret;
}
int compute(const char * exp)
{
LinkStack * stack = LinkStack_Create();
int ret = 0;
int i = 0;
while (exp[i] != '\0')
{
if (isNumber(exp[i]))
{
LinkStack_Push(stack, (void *)value(exp[i]));
}
else if (isOperator(exp[i]))
{
int right = (int)LinkStack_Pop(stack);
int left = (int)LinkStack_Pop(stack);
int result = express(left, right, exp[i]);
LinkStack_Push(stack, (void *)result);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
if ((LinkStack_Size(stack) == 1) && (exp[i] == '\0'))
{
ret = (int)LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
}
LinkStack_Destroy(stack);
return ret;
}
int main()
{
printf("8 + (3 - 1) * 5 = %d\n", compute("831-5*+"));
//system("pause");
return 0;
}