栈在表达式求值中的应用
2015-08-13 17:54
351 查看
一. 栈ADT
首先我们使用java来实现栈ADT,这里不使用java提供的Stack类, 而是使用ArrayList来实现,具体看代码:public class MyStack { public ArrayList<String> stack = new ArrayList<String>(); public String pop() { int index = stack.size()-1; String str = stack.get(index); stack.remove(index); return str; } public String peek() { int index = stack.size()-1; return stack.get(index); } public void push(String value) { stack.add(value); } public boolean isEmpty() { return stack.isEmpty(); } public int length() { return stack.size(); } }
二. 逆波兰式
表达式求值首先需要用将表达式转换成后缀表示式(由中缀表达式转成后缀表达(逆波兰式))。后缀表达在计算时就不需要考虑符号的优先级。1、利用栈来实现
/** * * @param expr * @return * 从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分; * 若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈, * 若优先级高于栈顶符合,将当前符号进栈,一直到最终输出后缀表达式为止。 */ public static String convert_suffix_expr(String expr) { String result = "", top = ""; ArrayList<String> al = new ArrayList<String>(); Pattern pattern = Pattern.compile("[0-9].*"); String[] str = expr.split(" "); for (String string : str) { Matcher matcher = pattern.matcher(string); boolean b = matcher.matches(); if (b) { //如果是数字 result += string + " "; } else { if (al.size() > 0) { top = al.get(al.size() - 1); } if (string.equals(")")) { do { if (!(al.get(al.size() - 1).equals("("))) { result += al.get(al.size() - 1) + " "; al.remove(al.size() - 1); } } while (al.size() > 0 && !al.get(al.size() - 1).equals("(")); al.remove(al.size() - 1); } else if (string.equals("(") || string.equals("*") || string.equals("/")) { al.add(string); } else { if (top.equals("*") || top.equals("/")) { do { result += al.get(al.size() - 1) + " "; al.remove(al.size() - 1); } while (al.size() > 0); al.add(string); } else { //处理+,- al.add(string); } } } } while (al.size() > 0) { result += al.get(al.size() - 1) + " "; al.remove(al.size() - 1); } return result; }
2、利用语法树来实现
先把中缀表达式用二叉树表示出来,再后序遍历该二叉树就得到相应的后缀表达式了。a.中缀表达式用二叉树表示
一般情况下并不能由一个中缀表达式得到一个唯一的二叉树,但是若由二叉树来表示表达式,叶子节点必须是操作数,非叶子节点是操作符,所以能够确定一个二叉树:转化过程如下:
按照优先级加上括号,得到:( 8 - ( (3 + 5) * ( 5 - (6 / 2) ) ) )
然后从最外层括号开始,依次转化成二叉树
1) 根是- ,左子树8,右子树( (3 + 5) * ( 5 - (6 / 2) ) )
2) 右子树的根*,右子树的左子树(3 + 5),右子树的右子树( 5 - (6 / 2) )
3) (3 + 5)的根+,左子树3 ,右子树5
4) ( 5 - (6 / 2) )的根-,左子树5,右子树(6 / 2)
5) (6 / 2)的根/,左子树6,右子树2
b. 树的遍历
下面是对图中树的遍历
这里的顺序针对的是非叶子节点
先序遍历:A B D G H E C K F I J
中序遍历:G D H B E A K C I J F
后序遍历:G H D E B K J I F C A
3、加括号法(在草稿上手工转换)
三. 表达式求值
最后我们通过栈来求取表达式的值public static void main(String[] args) { String expression = convert_suffix_expr("8 - ( ( 3 + 5 ) * ( 5 - ( 6 / 2 ) ) ) "); // System.out.println(expression); String[] str = expression.split(" "); MyStack myStack = new MyStack(); for (int i = 0; i < str.length; i++) { if (i<2) { myStack.push(str[i]); }else { if ("+".equals(str[i])) { String value1 = myStack.pop(); String value2 = myStack.pop(); int result = Integer.parseInt(value1)+Integer.parseInt(value2); myStack.push(String.valueOf(result)); }else if ("-".equals(str[i]) ) { String value1 = myStack.pop(); String value2 = myStack.pop(); int result = Integer.parseInt(value2)-Integer.parseInt(value1); myStack.push(String.valueOf(result)); }else if ("*".equals(str[i]) ) { String value1 = myStack.pop(); String value2 = myStack.pop(); int result = Integer.parseInt(value1)*Integer.parseInt(value2); myStack.push(String.valueOf(result)); }else if ("/".equals(str[i]) ) { String value1 = myStack.pop(); String value2 = myStack.pop(); int result = Integer.parseInt(value2)/Integer.parseInt(value1); myStack.push(String.valueOf(result)); } else { myStack.push(str[i]); } } } if (!myStack.isEmpty()) { System.out.println(myStack.pop()); } }
将中缀表达式转化为后缀表达式(栈用来进出运算的符号)。
将后缀表达式进行运算得出结果(栈用来进出运算的数字)。
相关文章推荐
- json解析和生成
- 红黑树 RBT
- Objective-C:ARC自动释放对象内存
- CSS related
- 平衡二叉树 AVL
- 页面访问的常见错误码解析
- Android的Message机制(简单小结)
- ZOJ 2048 :Highways 【Prim】
- SQL Server 内置函数、临时对象、流程控制
- Linux系统常用命令大全
- Android 表情功能的完整处理方案
- linux drm 架构
- OSG教程汇总
- Android的shape使用
- acid-事务的原子性、一致性、隔离性、持久性
- zoj2048Highways
- View覆盖status bar
- web项目中各种路径的获取
- 斯坦福ML公开课笔记13A——混合高斯模型、混合贝叶斯模型
- 【转载】利用MAVEN打包时,如何包含更多的资源文件