您的位置:首页 > 理论基础 > 数据结构算法

【数据结构和算法分析】栈与逆波兰式

2014-07-27 12:04 141 查看

栈ADT

:是限制插入和删除只能在一个位置上进行的表,该位置就是表的末端,或者栈的顶端(top)。对栈的基本操作有 push(进栈) 和 pop(出栈)。注意,对空栈进行的 pop 或 top 操作一般被认为是栈ADT的一个错误。另一方面,当运行 push 时空间用尽是一个实现限制,但不是ADT错误

栈的实现:由于栈是一个表,因此任何实现表的方法都能实现栈,所以在 java 中 ArrayList 和 LinkedList 都支持栈操作,99%的时间它们都是最合理的选择。栈的优势在于它的操作不仅是以常数时间运行,而且是以非常快的常数时间运行。即使是这样简单的结构与功能,却有着非常强大的作用

为了简单,用 ArrayList 实现一个具有基本功能的 MyStack

import java.util.ArrayList;

public class MyStack {

private ArrayList<Object> stack = new ArrayList<>();

public MyStack(){
}

/*
* 进栈
*/
public void push(Object object){
stack.add(object);
}
/*
* 出栈
*/
public void pop(){
if (stack.size() == 0) {
throw new IndexOutOfBoundsException();
}else{
stack.remove(stack.size()-1);
}
}
/*
* 返回栈顶元素
*/
public Object top(){
if (stack.size() == 0) {
throw new IndexOutOfBoundsException();
}else{
return stack.get(stack.size()-1);
}
}

public int length(){
return stack.size();
}

}


栈的应用

中缀表达式转后缀表达式

中缀表达式即标准形式的表达式。我们通过只允许操作+,-,*,/,(,),并坚持普通的优先级法则而将一般的问题浓缩成小规模的问题,比如,将中缀表达式 a + b * c + ( d * e + f ) * g  转换为后缀表达式就是 a b c * + d e * f + g * +

解法

1.遇到操作数,直接输出(添加到后缀表达式中)

2.栈为空时,遇到运算符,直接入栈

3.遇到左括号,将其入栈

4.遇到右括号,执行出栈操作,并将出栈的元素依次输出,直至弹出的是左括号,左括号不输出

5.遇到其他的运算符,加减乘除,依次弹出运算符优先级大于或者等于该运算符的的栈顶元素,然后将该运算符入栈

6.最终将栈内的元素依次出栈,输出

逆波兰式求值

逆波兰式,即后缀表达式

解法

从左往右扫描表达式,遇到数字时,将数字压入栈中,遇到运算符时,将栈顶的两个元素弹出,用运算符对它们进行相应的操作,并将结果入栈;重复上述步骤,到表达式扫描结束,最后运算得到的结果就是原表达式的结果。

附上代码:

import java.util.Stack;
import java.util.regex.Pattern;

public class PostFix {
private static String infixToSuffix(String infix) {
Stack<Character> stack = new Stack<Character>();
String suffix = "";
int length = infix.length();
for (int i = 0; i < length; i++) {
Character temp;
char c = infix.charAt(i);
switch (c) {
// 忽略空格
case ' ':
break;

// 碰到'(',push到栈
case '(':
stack.push(c);
break;

// 碰到'+''-',将栈中所有运算符弹出,送到输出队列中
case '+':
case '-':
while (stack.size() != 0) {
temp = stack.pop();
if (temp == '(') {
stack.push('(');
break;
}
suffix += " " + temp;
}
stack.push(c);
suffix += " ";
break;

// 碰到'*''/',将栈中所有乘除运算符弹出,送到输出队列中
case '*':
case '/':
while (stack.size() != 0) {
temp = stack.pop();
if (temp == '(' || temp == '+' || temp == '-') {
stack.push(temp);
break;
} else {
suffix += " " + temp;
}
}
stack.push(c);
suffix += " ";
break;

// 碰到右括号,将靠近栈顶的第一个左括号上面的运算符全部依次弹出,送至输出队列后,再丢弃左括号
case ')':
while (stack.size() != 0) {
temp = stack.pop();
if (temp == '(')
break;
else
suffix += " " + temp;
}
break;

default:
suffix += c;
}
}

while (stack.size() != 0)
suffix += " " + stack.pop();
return suffix;
}

// 通过后缀表达式求出算术结果
private static double suffixToArithmetic(String postfix) {
Pattern pattern = Pattern.compile("\\d+||(\\d+\\.\\d+)"); // 匹配数字
String strings[] = postfix.split(" ");
for (int i = 0; i < strings.length; i++)
strings[i].trim();
Stack<Double> stack = new Stack<Double>();
for (int i = 0; i < strings.length; i++) {
if (strings[i].equals(""))
continue;
if ((pattern.matcher(strings[i])).matches()) {
stack.push(Double.parseDouble(strings[i]));
} else {
double y = stack.pop();
double x = stack.pop();
stack.push(caculate(x, y, strings[i]));
}
}
return stack.pop();
}

private static double caculate(double x, double y, String simble) {
if (simble.trim().equals("+"))
return x + y;
if (simble.trim().equals("-"))
return x - y;
if (simble.trim().equals("*"))
return x * y;
if (simble.trim().equals("/"))
return x / y;
return 0;
}

public static void main(String args[]) {
System.out.println(infixToSuffix("2+(5-2*2)*3"));
System.out.println(suffixToArithmetic(infixToSuffix("2+(5-2*2)*3")));
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: