
- 表达式就是由变量、常量以及运算符组合而成的式子。
- 如何用栈结构求一个表达式的值?
1、后缀表达式
- 1929 年,波兰逻辑学家 J・卢卡西维兹提出了一种全新的表示表达式的方法,称为后缀表达式或逆波兰表达式。和普通表达式不同,后缀表达式习惯将运算符写在它的运算项之后,且整个表达式中不用括号
()
表明运算的优先级关系。
-
- 以
3!
为例,! 为运算符,3 为运算项,因此3!
本身就是一个后缀表达式
- 再以 4*2 为例,* 为运算符,4 和 2 作为它的运算项,其后缀表达式为
4 2 *
- 将
3!+4*2/(1-5)^2
转换成后缀表达式(将表达式中所有运算符放置在它的运算项之后):
-
- ! 运算符对应的运算项为 3,转换后得到
3 !
- + 运算符对应的运算项是
3!
和4*2/(1-5)^2
,转换之后得到:3! 4*2/(1-5)^2 +
- * 运算符对应的运算项是 4 和 2,转换之后得到
4 2 *
- / 运算符对应的运算项是
4 2 *
和 (1-5)^2
,转换后得到4 2 * (1-5)^2 /
- - 运算符对应的运算项是 1 和 5,转换后得到
1 5 -
- ^ 运算符对应的运算项是
1 5 -
和 2 ,转换后得到1 5 - 2 ^
- 整合之后,整个普通表达式就转换成了
3 ! 4 2 * 1 5 - 2 ^ / +
,这就是其对应的后缀表达式
- 后缀表达式完全舍弃了表达式本该有的可读性,相比普通表达式,后缀表达式的值可以借助栈存储结构求得。具体求值的过程:当用户给定一个后缀表达式时,按照从左到右的顺序依次扫描表达式中的各个运算项和运算符,对它们进行如下处理:
-
- 遇到运算项时,直接入栈
- 遇到运算符时,将位于栈顶的运算项出栈:
-
-
- 对于 ! 运算符,取栈顶 1 个运算项
- 其它运算符则取栈顶 2 个运算项,第一个取出的运算项作为该运算符的右运算项,另一个作为左运算项
- 重复以上操作,直到栈中仅存在一个运算项为止,此运算项即为整个表达式的值。
- 以
3 ! 4 2 * 1 5 - 2 ^ / +
表达式为例,求值的过程为:

-
- ! 作为运算符,从栈顶取一个运算项 3,求
3!
的值(3! = 3*2*1=6
)并将其入栈:

-
- 将 4 和 2 先后入栈:

- 对于 * 运算符,取栈顶两个运算项( 2 和 4),先取出的 2 作为 * 的右操作数,4 作为左操作数。求的
4 * 2
的值 8 ,并将其入栈:


-
- 对于 - 运算符,取栈顶两个运算项(5 和 1),计算出
1-5
的值为 -4
,将其入栈:


-
- 对于 ^ 运算符,取栈顶两个运算项(2 和 -4),计算出
-4^2
的值 16 ,将其入栈:

-
- 对于 / 运算符,取栈顶两个运算项(16 和 8),计算出
8/16
的值 0.5,将其入栈:

-
- 对于 + 运算符,取栈顶两个运算符(0.5 和 6),计算出
6+0.5
的值 6.5,将其入栈:

- 由此,整个求值的过程就结束了,最终表达式的值为 6.5。
- 代码实现:
// 根据给定的后缀表达式 postexp,计算它的值
typedef struct
{
double data[MAXSIZE];
int top;
}Stack_num;
void InitStack_num(Stack_num **s)
{
*s = (Stack_num *)malloc(sizeof(Stack_num));
(*s)->top = -1;
}
bool Push_num(Stack_num **s, double e)
{
if ((*s)->top == MAXSIZE - 1)
return false;
(*s)->top++;
(*s)->data[(*s)->top] = e;
return true;
}
bool Pop_num(Stack_num **s, double *e)
{
if ((*s)->top == -1)
return false;
*e = (*s)->data[(*s)->top];
(*s)->top--;
return true;
}
// 计算后缀表达式的值
double compvalue(char *postexp)
{
Stack_num *num;
int i = 1;
double result;
double a, b;
double c