利用基于栈结构的逆波兰表达式实现四则运算

1.涉及概念

1.1 栈

栈是一种操作受限的线性表,即只允许从一端插入和删除数据,他的存储方式分为线性存储和链接存储。栈的一个最重要的特征就是栈的插入和删除只能在栈顶进行,所以每次删除的元素都是最后进栈的元素,故栈也被称为后进先出(LIFO)表。栈主要有两种操作,分为入栈(push)和出栈(pop)。由于只操作栈顶元素,所以此操作的复杂度为O(1)。

1.2 逆波兰表达式

逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasewicz)于1929年首先提出的一种表达式的表示方法后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)*(c+d)转换为ab+cd+*。如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。

2.前提说明

本篇文章重点是说明四则运算转换成逆波兰表达式,最后计算表达式结果,所以本次只考虑四则运算。接下来,我们会以一个例子讲解运算过程。

四则运算表达式:

3 + 4 * (5 + 6 / 7) / (8 - 9) - 10 + 11 

3.四则运算表达式转换为逆波兰表达式

3.1 总体思路

从左到右遍历中缀表达式的每个数字和符号,若是数字则直接输出,若是符号,则判断其于栈顶符号的优先级,是有括号或者优先级低于栈顶符号,则栈顶元素依次出栈并输出,直到遇到左括号或栈空才将之前那个符号入栈。

3.2 变量声明

为说明方便简单,这里设定逆波兰表达式为exp,符号栈为stack。以下每一步骤处理一个字符。

3.2 具体步骤

01)"3"为数字,所以输出3。此时exp为{3};stack为{}。

02)"+"为符号,并且栈顶为空,所以压入栈顶。此时exp为{3};stack为{+}。

03)"4"为数字,所以输出4。此时exp为{3 4} ;stack为{+}。

04)"*"为符号,此时栈顶元素为"+",并且优先级小于"*",所以"*"压人栈顶。此时exp为{3 4},stack为{+ *}。

05)"("为符号,并且为左括号,所以"("压人栈顶。此时exp为{3 4},stack为{+ * (}。

06)"5"为数字,所以输出5。此时exp为{3 4 5} ;stack为{+ * (}。

07)"+"为符号,此时栈顶元素为"(",所以"+"压人栈顶。此时exp为{3 4 5 },stack为{+ * ( +}。

08)"6"为数字,所以输出6。此时exp为{3 4 5 6} ;stack为{+ * ( +}。

09)"/"为符号,此时栈顶元素为+,优先级低于"/",所以"/"压入栈顶。此时exp为{3 4 5 6} ;stack为{+ * ( + /}。

10) "7"为数字,所以输出7。此时exp为{3 4 5 6 7} ;stack为{+ * ( + /}。

11)")"为符号,并且为右括号。所以依次将栈内左括号"("以前的运算符号依次弹出。此时exp为{3 4 5 6 7 / +};stack为{+ *}。

12)"/"为运算符号,此时栈顶元素为"*",优先级等于"/",所以弹出栈顶元素"*;接下来,此时栈顶元素为"+",优先级低于"/",所以压入栈顶。此时exp为{3 4 5 6 7 / + *};stack为{+ /}。

13)"("为符号并且为左括号,所以压入栈顶。此时exp为{3 4 5 6 7 / + *};stack为{+ / (}。

14)"8"为数字,所以输出8。此时exp为{3 4 5 6 7 / + * 8};stack为{+ / (}。

15)"-"为符号,栈顶元素为"(",所以直接压入栈顶。此时exp为{3 4 5 6 7 / + * 8};stack为{+ / ( -}。

16)"9"为数字,所以输出9。此时exp为{3 4 5 6 7 / + * 8 9};stack为{+ / ( -}。

17)")"为符号且为有括号,将栈中左括号以前的运算符弹出栈。此时exp为{3 4 5 6 7 / + * 8 9 -};stack为{+ / }。

18)"-"为运算符号,此时栈顶元素为"/",优先级大于"-",所以弹出栈顶元素"/";此时栈顶元素为"+",优先级等于"-",所以弹出栈顶元素"+",同时将"-"压如栈顶。此时exp为{3 4 5 6 7 / + * 8 9 - / +};stack为{- }。

19)"10"为数字,所以输出10。此时exp为{3 4 5 6 7 / + * 8 9 - / + 10};stack为{- }。

20)"+"为运算符号,此时栈顶元素为"-",优先级等于"+",所以弹出栈顶元素,同时将"+"压如栈顶。此时exp为{3 4 5 6 7 / + * 8 9 - / + 10 -};stack为{+ }。

21)"11"为数字,所以输出11。此时exp为{3 4 5 6 7 / + * 8 9 - / + 10 - 11};stack为{+ }。

22)将栈内元素依次弹出。所以最终的exp为{3 4 5 6 7 / + * 8 9 - / + 10 - 11 + }。

4.基于栈的逆波兰表达式运算

4.1 总体思路

遍历逆波兰表达式的每个元素,如果为数字,则压入栈顶;如果是符号,则弹出栈顶两个元素,将数据进行运算,得到的数据压入栈顶。

4.2 前提

通过上面计算的表达式为{3 4 5 6 7 / + * 8 9 - / + 10 - 11 + }。

4.3 变量声明

为说明方便简单,这里涉及到一个栈,我们定义为stack.

4.4 计算步骤

1)3为数字,压入栈顶。此时stack为{3}。

2)4为数字,压入栈顶。此时stack为{3 4}。

3)5为数字,压入栈顶。此时stack为{3 4 5}。

4)6为数字,压入栈顶。此时stack为{3 4 5 6}。

5)7为数字,压入栈顶。此时stack为{3 4 5 6 7}。

6)"/"为符号,此时弹出栈顶两个元素为6和7,所以将6和7做"/"运算,得到数据为0.857。并将0.857压入栈顶。

    此时stack为{3 4 5 0.857}。

7)"+"为符号,此时弹出栈顶两个元素为5和0.857,所以将5和0.857做"+"运算,得到数据为5.857。并将5.857压入栈顶。

    此时stack为{3 4 5.857}。

8)"*"为符号,此时弹出栈顶两个元素为4和5.857,所以将4和5.857做"*"运算,得到数据为23.428。并将23.428压入栈顶。

    此时stack为{3 23.428}。

9)8为数字,压入栈顶。此时stack为{3 23.428 8}。

9)9为数字,压入栈顶。此时stack为{3 23.428 8 9}。

10)"-"为符号,此时弹出栈顶两个元素为8和9,所以将8和9做"-"运算,得到数据为-1。并将-1压入栈顶。

    此时stack为{3 23.428 -1}。

11)"/"为符号,此时弹出栈顶两个元素为23.428和-1,所以将23.428和-1做"/"运算,得到数据为-23.428。并将-23.428压入栈顶。

    此时stack为{3 -23.428}。

11)"+"为符号,此时弹出栈顶两个元素为3和 -23.428,所以将3和 -23.428做"+"运算,得到数据为-20.428。并将-20.428压入栈顶。

    此时stack为{-20.428}。

12)"10"为数字,压入栈顶。此时stack为{-20.428 10}。

13)"-"为符号,此时弹出栈顶两个元素为-20.428和10,所以将-20.428和10做"-"运算,得到数据为-30.428。并将-30.428压入栈顶。

    此时stack为{-30.428}。

14)"11"为数字,压入栈顶。此时stack为{-30.428 11}。

15)"+"为符号,此时弹出栈顶两个元素为-30.428和11,所以将-30.428和11做"+"运算,得到数据为-19.428。并将-19.428压入栈顶。

    此时stack为{-19.428}。

16)逆波兰表达式遍历完毕,此时栈顶的数据即为计算的结果。为-19.428。

17)我们通过计算器计算得到的结果为:-19.429

发布了72 篇原创文章 · 获赞 24 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/oYinHeZhiGuang/article/details/103643125
今日推荐