栈的应用---简单表达式求值问题

简单表达式求值

写在前面:本文的参考资料:数据结构教程(第五版) 李春葆 主编 清华大学出版社

问题描述

这里限定的简单表达式求值问题是用户输入一个包含+、-、*、/、正整数和圆括号的合法算术表达式,计算该表达式的运算结果。

数据组织

简单表达式采用字符数组exp表示,其中只含有+、-、*、/、正整数和圆括号。为了方便,假设该表达式都是合法的算术表达式,例如exp=“1+2*(4+12)”,在设计相关算法中用到栈,这里采用顺序存储结构

设计运算算法

  • 在算术表达式中,有三种常用的表达式
    1. 中缀表达式
    *特点:*运算符位于两个操作符之间,日常生活中最常用的表达式。运算遵循“先乘除、后加减,从左到右计算,先括号内,后括号外”的规则,因此中缀表达式不仅要依赖运算符优先级,还有处理括号。
    2. 后缀表达式
    又称为“逆波兰表达式”,运算符在操作数的后面,如1+2*3的后缀表达式为1 2 3 * +。在后缀表达式中已经考虑了运算符的优先级,没有括号,只有操作数和运算符,而且越放在前面的运算符越优先执行
    3. 前缀表达式
    运算符在操作数的前面,如如1+2*3的前缀表达式为+ 1 * 2 3 。
    结论后缀表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。所以对中缀表达式求值的过程是先将中缀算术表达式转换成后缀表达式,然后对后缀表达式求值。
  • 将算术表达式转化为后缀表达式
    • 在将一个中缀表达式转换成后缀表达式时,操作数之间的相对次序是不变的,但运算符的相对次序可能不同,同时还要除去括号。所以在转换时需要从左到右扫描算术表达式,将遇到的操作数直接存放在后缀表达式中,将遇到的每一个运算符或者左括号都暂时存放在栈中,而且先执行的运算符先出栈。
    • 假设用exp字符数组存储满足前面条件的简单中缀表达式,其对应的后缀表达式存放在字符数组postexp中。
    • 归纳1:在扫描exp遇到一个运算符op时,如果栈为空,直接将其进栈;如果栈不空,只有当op的优先级高于栈顶运算符的优先级时才直接将op进栈(以后op先出栈表示先执行它);否则依次出栈运算符并存入postexp(出栈的运算符都比op先执行),直到栈顶元素的优先级小于op的优先级为止,然后将op进栈。
    • 归纳2:在扫描exp遇到一个运算符op时,如果op为’(’,表示一个子表达式的开始,直接将其进栈;如果op为‘)’,表示一个子表达式的结束,需要出栈运算符并存入到postexp,直到栈顶为‘(’,再将‘(’出栈;如果op是其他运算符,而栈顶为‘(’,直接将其进栈。
    • 设置一个运算符栈Optr,初始时为空。为了方便后面将数值串转换为对应的数值,在后缀表达式中的每个数字末尾添加一个‘#’。将算术表达式exp转换成后缀表达式postexp的过程如下:
while (从exp读取字符ch,ch! = '\0')
{
   
   ch 为数字 :将后续的所有数字依次存放到postexp中,并以字符‘#’标识数字串结束;
   ch 为左括号 '(':将此括号进栈到Optr中;
   ch 为右括号 ')':将Optr中出栈时遇到的第一个左括号‘(’以前的运算符依次出栈并存放到postexp中,然后将左括号‘(’出栈;
   ch 为其他运算符:
   	if(栈空或者栈顶元素为‘(’) 直接将ch进栈;
   	else if(ch的优先级高于栈顶运算符的优先级)
   		直接将ch进栈;
   	else
   		依次出栈并存入到postexp中直到ch的优先级高于栈顶运算符,然后将ch进栈;
}
若exp扫描完毕,则将OPtr中的所有运算符依次出栈并存放到postexp中。
  • 对于简单的算术表达式,‘+’和‘-’运算符的优先级相同,‘*’和‘/’运算符的优先级相同,只有‘*’和‘/’运算符的优先级高于‘+’和‘-’运算符的优先级。所以上述过程进一步改为如下:
while (从exp读取字符ch,ch! = '\0')
{
   
   ch 为数字 :将后续的所有数字依次存放到postexp中,并以字符‘#’标识数字串结束;
   ch 为左括号 '(':将此括号进栈到Optr中;
   ch 为右括号 ')':将Optr中出栈时遇到的第一个左括号‘(’以前的运算符依次出栈并存放到postexp中,然后将左括号‘(’出栈;
   ch 为'+''-':出栈运算符并存放到postexp中,直到栈空或者栈顶为‘(’,然后将ch进栈;
   ch 为'*''/':出栈运算符并存放到postexp中,直到栈空或者栈顶为‘(’、‘+’、‘-’,然后将ch进栈;
   
}
若exp扫描完毕,则将OPtr中的所有运算符依次出栈并存放到postexp中。
  • 将后缀表达式求值
    • 后缀表达式的求值过程,就是从左到右扫描后缀表达式postexp,若读取到的是一个操作数,将它进操作数栈,若读取的是一个运算符op,从操作数栈中连续出栈两个操作数,假设为a(第一个出栈元素)和b(第二个出栈元素),计算b op a的值,并将计算结果进操作数栈。当整个后缀表达式扫描结束时,操作数栈中的栈顶元素就是表达式的计算结果。
    • 在后缀表达式求值算法设计中操作数栈为Opnd,用于临时存放将要进行某种算术运算的操作数。
while (从postexp读取字符ch,ch != '\0')
	{
   
		ch 为'+':从Opnd栈中出栈两个操作数a和b,计算c=b+a,将c进栈;
		ch 为'-':从Opnd栈中出栈两个操作数a和b,计算c=b-a,将c进栈;
		ch 为'*':从Opnd栈中出栈两个操作数a和b,计算c=b*a,将c进栈;
		ch 为'/':从Opnd栈中出栈两个操作数a和b,,若a不零,计算c=b/a,将c进栈;
		ch 为数字字符:将连续的数字串转换成数值d,将d进栈;
	}
	返回Opnd的栈顶操作数(即后缀表达式的值);

程序设计

头文件 顺序栈存储类型->运算符栈

#pragma once
#define MaxSize 50
typedef char ElemType;

typedef struct 
  • 12
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值