棧的應用--四則運算表示式求值(java語言)
阿新 • • 發佈:2019-02-07
棧的應用–四則運算表示式求值(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());
}
}