您的位置:首页 > 其它

栈在表达式求值中的应用

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());
}
}


将中缀表达式转化为后缀表达式(栈用来进出运算的符号)。

将后缀表达式进行运算得出结果(栈用来进出运算的数字)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: