栈的应用–四则运算表达式求值(java语言)
前言
在复习数据结构的过程中,采用单链表实现了栈Stack,具体功能有如下几个功能:判断其是否为空栈、输出栈的长度、入栈、出栈并且实现Iterable借口,可以采用Iterator遍历栈。在测试了栈之后,觉得应该将栈应用一下,于是在看书大话数据结构中,发现可以将栈应用到四则运算表达式求值中,这样我就想着去实现一下,想达到的目的是:当输入一个表达式,例如:9+(3-1)*3+10/2,可以得到其输出为20.
后缀(逆波兰)表示法定义
后缀表示法是由波兰的一位逻辑学家(名字太长,我就不写了)为了使用计算机解决四则运算问题而提出的,是一种不需要括号的后缀表达法,比如四则运算表达式9+(3-1)×3+10/2,其后缀表达式为931-3×+102/+,叫后缀的原因在于所有的符号都是在要运算数字的后面出现。
单链表实现栈的代码如下:
package ApplyStack;
import java.util.Iterator;
/**
* 链表表头操作实现下压栈
*
* @author 七分帅气
* @date 2016.7.20
* @param <Item>
*/
public class Stack<Item> implements Iterable<Item> {
private Node first; // 表示链表的表头同时也表示栈顶
private int N; // 链表的长度
private class Node {
Item data;
Node next;
public Node(Item data) {
this.data = data;
}
}
public boolean isEmpty() {
return first == null;
}
public int size() {
return N;
}
public void push(Item item) {
Node oldFirst = first;
first = new Node(item);
first.next = oldFirst;
N++;
}
public Item pop() {
Item temp = first.data;
first = first.next;
N--;
return temp;
}
@Override
public Iterator<Item> iterator() {
return new ListIterator();
}
private class ListIterator implements Iterator<Item> {
private Node current = first;
@Override
public boolean hasNext() {
return current != null;
}
@Override
public Item next() {
Item item = current.data;
current = current.next;
return item;
}
@Override
public void remove() {
}
}
}
后缀表达式计算结果的规则
规则如下:从左到右遍历表达式的每个数字和符号,遇到是数字进栈,遇到是符号,就将处于栈顶的两个数字出栈进行运算,运算结果进栈,一直到最终获得结果(具体详见大话数据结构106页)。
java实现代码如下:
class PostToResult{
private String post; //中缀表达式转换得到的后缀表达式
private Stack<Integer> stack; //用于得到计算结果的栈
public PostToResult(String post, Stack<Integer> stack) {
this.post = post;
this.stack = stack;
}
//由后缀表达式得到四则运算结果的实现过程
public void operate(){
String[] strArr = post.split(" ");
for(int i = 0; i < strArr.length; i++){
String temp = strArr[i];
if(isDigital(temp)){
stack.push(Integer.valueOf(temp));
}else{
int result = compute(temp);
stack.push(result);
}
}
}
private int compute(String str){
int re = 0;
int m = stack.pop();
int n = stack.pop();
switch(str){
case "+" :
re = n + m;
break;
case "-" :
re = n - m;
break;
case "*" :
re = n * m;
break;
case "/" :
re = n / m;
break;
default :
break;
}
return re;
}
private boolean isDigital(String str){
char[] chArr = str.toCharArray();
int len = chArr.length;
int count = 0;
for(int i = 0; i < len; i++){
if(chArr[i] >= '0' && chArr[i] <= '9')
count++;
}
return count == len;
}
public int getResult() {
return stack.pop();
}
}
虽然后缀表达式有这样的优点,可是我们输入的是中缀表达式,所以需要将中缀表达式转换为后缀表达式。
中缀表达式转后缀表达式的规则
规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止(具体详见大话数据结构108页)。
java实现代码如下:
package ApplyStack;
/**
* 栈的应用:四则运算表达式求值
* @author 七分帅气
* @date 2016.7.20
*/
public class InfixToPost {
private Stack<String> stack; //中缀表达式转换为后缀表达式所需要的栈
private String infix; //输入的中缀表达式
private String post = ""; //存储得到的后缀表达式
//初始化构造器
public InfixToPost(Stack<String> stack, String infix) {
this.stack = stack;
this.infix = infix;
}
/**
*
* @param infix 输入的中缀表达式
* @return 返回处理过后的中缀表达式,主要是在输入的中缀表达式加空格
* 例如:输入的中缀表达式为:9+(3-1)*3+10/2
* 输出的中缀表达式为:9 + ( 3 - 1 ) * 3 + 10 / 2
*/
private String processInfix(String infix) {
String result = "";
for (int i = 0; i < infix.length() - 1; i++) {
char temp1 = infix.charAt(i);
char temp2 = infix.charAt(i + 1);
if (isDigital(temp1) && isDigital(temp2)) {
result += temp1;
} else {
result += temp1 + " ";
}
}
result += infix.charAt(infix.length() - 1); // 将最后一个元素添加进去
return result;
}
private boolean isDigital(char ch) {
if (ch >= '0' && ch <= '9')
return true;
else
return false;
}
//将前缀表达式转换为后缀表达式的处理过程
public void process() {
String[] strArr = processInfix(infix).split(" ");
for (int i = 0; i < strArr.length; i++) {
String str = strArr[i];
switch (str) {
case "+":
case "-":
getOperation(str, 1);
break;
case "*":
case "/":
getOperation(str, 2);
break;
case "(":
stack.push(str);
break;
case ")":
getParent();
break;
default:
post += " " + str;
break;
}
}
// 数字全部输出后,需要输出栈中剩余的符号
while (!stack.isEmpty()) {
post += " " + stack.pop();
}
}
private void getParent() {
while (!stack.isEmpty()) {
String top = stack.pop();
if (top.equals("(")) {
break;
} else {
post += " " + top;
}
}
}
private void getOperation(String str, int priority) {
while (!stack.isEmpty()) {
String top = stack.pop();
if (top.equals("(")) {
stack.push(top);
break;
} else {
int priTop = getPriority(top);
if (priTop < priority) {
stack.push(top);
break;
} else {
post += " " + top;
}
}
}
stack.push(str);
}
private int getPriority(String str) {
int pri = 0;
if (str.equals("+") || str.equals("-")) {
pri = 1;
} else {
pri = 2;
}
return pri;
}
public String getPost() {
return post.trim();
}
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
String input = "9+(3-1)*3+10/2";
InfixToPost infix = new InfixToPost(stack, input);
infix.process();
String post = infix.getPost();
Stack<Integer> stack_result = new Stack<>();
PostToResult ptr = new PostToResult(post, stack_result);
ptr.operate();
System.out.println(ptr.getResult());
}
}