【数据结构和算法分析】栈与逆波兰式
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")));
}
}
相关文章推荐
- 常用的算法和数据结构分析(跳表和散列)
- 数据结构和算法分析实验(一)
- 算法数据结构C++实现8 堆排序 难点分析
- 一步步学习数据结构和算法之折半插入排序效率分析及java实现
- 一步步学习数据结构和算法之直接插入排序效率分析及java实现
- 常用的算法和数据结构分析(二叉树)
- 一步步学习数据结构和算法之堆排序效率分析及java实现
- 读书笔记——数据结构(2)算法分析
- 读书笔记——数据结构(2)算法分析
- 一步步学习数据结构和算法之希尔排序效率分析及java实现
- 数据结构和算法分析实验(二)
- 一道简单题目的数据结构算法分析
- 数据结构和算法分析学习笔记(三)--二叉查找树的懒惰删除(lazy deletion)
- 数据结构和算法分析
- KMP算法之NEXT数组代码原理分析 - 数据结构和算法38
- 数据结构:递归 算法分析
- MP3解码算法分析——MP3帧头(Frame Header)数据结构描述
- 栈和队列5|逆波兰计算器 - 数据结构和算法27
- 一步步学习数据结构和算法之快速排序效率分析及java实现
- 一步步学习数据结构和算法之归并排序效率分析及java实现