表达式求值是栈这种数据结构的一个很经典的应用,恰逢是数据结构期末实践题目,经过一定的努力终于也是实现了这个算法,所以分享下我的思路和经验,希望正准备尝试解决这个问题的同学可以少走些弯路,有所借鉴和收获。
个人水平有限,文笔拙劣,有所意见和建议欢迎指出
我们日常使用的四则运算式如 1+1 被称为中缀表达式,即所有的运算符号都在运算数的中间出现,我们在初学编程时都练习过简单的二元运算,但当求值问题扩大到一个完整的四则运算式的时候,就需要考虑运算符优先级、括号等多个问题,解决了这些问题也就实现了表达式求值。
表达式求值问题常用的也是最广泛的解决方法是逆波兰式转换法,主要步骤可简单分为两步,用户输入的中缀表达式转化为后缀表达式(逆波兰式),再对逆波兰式进行运算。但在编程过程中我发现简单的分为两步是行不通的,因为涉及到多位数和浮点数,由于输入时统一存储为字符串,在进行中缀到后缀的转换后无法得到正确的后缀式字符串,由于c语言中char型数据实际上也是int型数据,这就进一步增加了正确转换的难度,从而也就无法在逆波兰式的计算中得出正确的结果,所以在编程实现时将这两步合为一个函数实现,即以字符串形式存储键盘输入的表达式后,对该字符串逐位处理,通过ASCII码值的判断分为数字或小数点、运算符两种情况,然后按照判断结果执行相应的语句。
准备工作
创建一char型数组用于存储输入的中缀表达式,在中缀表达式向后缀表达式的转化以及后缀表达式的计算中(详情见各种数据结构教材或书籍,或相关博客,实现此算法必须要实现了解这些过程)我们知道,因为涉及到运算符优先级的判断和后缀表达式的计算的部分我们需要借助栈来实现,所以需要创建一double型栈和一char型栈,分别用于存储操作数和运算符,栈的存储可随意选用线性结构或链式结构,需要实现以下操作函数:
- 初始化
- 出栈
- 入栈
- 取栈顶
- 判空
接下来对如何处理输入的表达式做详细介绍
1.数字或小数点(非运算符)
上图为ASCII码对照表
通过ASCII码我们可以得出输入的是数字(0-9)的条件,但因为存在多位数的情况,所以当前数字可能是输入的操作数的十位或百位等,所以不能简单的压入数字栈就完事,我的解决方法是每当遇到数字位都进行一次判断,检查表达式字符串中它的前一位是否为数字,若是,则说明这是个多位数,则将前一位(已入栈)出栈与10的n次幂做乘积后与当前位求和再入栈;对于例如12.34这类浮点数,则在判断当前位不是运算符后首先检查是否为小数点,若是则说明直到下一个运算符都是该浮点数的小数位,则与求多位整数(例12.34的整数位)值类似,与10的负n次幂做乘积累加求和知道遇到下一个运算符时入栈。