例三、算術表達式求值
1、問題描述
當一個算術表達式中含有多個運算符,且運算符的優先級不同的情況下,如何才能處理一個算術表達式?????
2、思路
首先我們要知道表達式分為 三類:
①中綴表達式:a+(b-c/d)*e
②前綴表達式+a*-b
e
③后綴表達式abcd/-e*+
由於運算符有優先級,所以在計算機中計算一個中綴的表達式非常困難,特別是帶括號的更麻煩,而后綴表達式中既無運算符優先又無括號的約束問題因為在后綴表達式中運算符出現的順序正是計算的順序,所以計算一個后綴的表達式更簡單。
所以,可以將求算術表達式的值的過程化成兩個過程:
1.將一個中綴表達式化成一個后綴表達式
2.對后綴表達式進行求值
1、問題描述
當一個算術表達式中含有多個運算符,且運算符的優先級不同的情況下,如何才能處理一個算術表達式?????
2、思路
首先我們要知道表達式分為 三類:
①中綴表達式:a+(b-c/d)*e
②前綴表達式+a*-b

③后綴表達式abcd/-e*+
由於運算符有優先級,所以在計算機中計算一個中綴的表達式非常困難,特別是帶括號的更麻煩,而后綴表達式中既無運算符優先又無括號的約束問題因為在后綴表達式中運算符出現的順序正是計算的順序,所以計算一個后綴的表達式更簡單。
所以,可以將求算術表達式的值的過程化成兩個過程:
1.將一個中綴表達式化成一個后綴表達式
2.對后綴表達式進行求值
一、將中綴變成一個后綴
因為要將運算符出現的次序與真正的算術運算順序一直, 所以,就要讓優先級高的以及括號內的運算符出現在前面,
因此要使用一個棧來保留還未送往后綴表達式的運算符,此棧稱為運算符棧
算法描述如下:
(1)初始化一個運算符棧
(2)從算術表達式輸入的字符串中,從左到右的讀取一個字符
(3)若當前的 字符是操作數,則直接送往后綴表達式
(4)若當前的字符是左括號,則將其壓入運算符棧
(5)若當前的字符是操作符,則進行如下 操作:
①當運算符棧為空時,直接將其壓入棧。
②當此運算符的優先級高於棧頂的運算符時,則將此運算符壓入棧,否則,彈出棧頂運算符送往后綴式,並將當前運算符壓棧,重復步驟(5)
(6)若當前字符是右括號,反復將棧頂符號彈出,並送往后綴表達式中,知道棧頂元素為左括號為止,然后將左括號出棧並丟棄
(7)若讀取還未結束,則重復步驟(2)
(8)若讀取結束,則將棧中剩余的所有的運算符彈出並送往后綴表達式
二、計算后綴表達式的值
計算步驟很簡單,就是找到運算符,然后找前面最后出現的兩個操作數,從而構成一個最小的算術表達式進行運算,
在計算過程中也需要利用一個棧來保留后綴表達式中還未參與運算的操作數,稱為操作數棧,
算法描述如下:
(1)初始化一個操作數棧
(2)從左到右依次讀入后綴表達式中的字符
①若當前字符是操作數,則壓入操作數棧。
②若當前字符是操作符,則從棧頂彈出兩個操作數參與運算,並將運算結果壓入操作數棧內。
(3)重復步驟(2)直到讀入的后綴表達式結束為止,則操作數棧中的棧頂元素即為后綴表達式的結果
3、代碼實現
package org.Stone6762.MStack.adopt;
import java.util.Scanner;
import org.Stone6762.MStack.imple.LinkStack;
/**
* @author_Stone6762
*/
public class ArithExpEvaluation {
/**
* @Describe_將原始的表達式轉換成一個后綴表達式
* @param expression原始的表達式
* @return與元素表達式相對於的后綴表達式
* @throws Exception
*/
public String conver2Postfix(String expression) throws Exception {
LinkStack st = new LinkStack();// 運算符棧
String postFix = "";// 后綴表達式
for (int i = 0; expression != null && i < expression.length(); i++) {
char c = expression.charAt(i);// 遍歷,如果是操作數,如果是操作符
if (' ' != c) {// 字符不能為空
if (isOpenParenthesis(c)) {// 左括號
// 左括號就入棧
st.push(c);
} else if (isCloseParenthesis(c)) {// 右括號
// 右括號就把所有的操作符出棧知道遇到一個左括號為止,然后將該左括號出棧並丟棄
Character ac = (Character) st.pop();
while (!isOpenParenthesis(ac)) {
postFix += ac.toString();
ac = (Character) st.pop();// 如果取出的是左括號,很顯然就丟棄了
}
} else if (isOperator(c)) {// 操作符
/*
* 如果棧為空,直接進棧。 如果棧非空,則需要將棧頂運算符的優先級和要入棧的運算符的優先級進行比較
* 將棧中比要入棧的運算符優先級高的運算符都出棧,然后將該運算符入棧
*/
if (!st.isEmpty()) { // 如果棧非空,則需要判斷
Character ac = (Character) st.pop();
while (ac != null
&& priority(ac.charValue()) > priority(c)) {
postFix += ac;
ac = (Character) st.pop();
// 因為是先取出來后判斷是,所以如果跳出循環 需要將最后一次取出的操作符壓入棧
}
// 將最后一次取出的優先級低的運算符入棧
if (ac != null) {
st.push(ac);
}
}
// 最后,將該運算符入棧
st.push(c);
} else {// 操作數,直接添加到后綴表達式 中
postFix += c;
}
}
}
// 最后的時候,如果棧非空,則需要棧中的所有的運算符串聯到后綴表達式的末尾
while (!st.isEmpty()) {
postFix += st.pop().toString();
}
return postFix;
}
/**
* @Describe_對后綴表達式進行運算
* @param postFix后綴表達式
* @return計算后的結果
* @throws Exception
*/
public double numberCalculate(String postFix) throws Exception {
LinkStack st = new LinkStack();// 操作數棧
for (int i = 0; i < postFix.length(); i++) {
char c = postFix.charAt(i);
if (isOperator(c)) {
double d2 = Double.valueOf(st.pop().toString());
double d1 = Double.valueOf(st.pop().toString());
double d3 = 0;
switch (c) {
case '+':
d3=d1+d2;
break;
case '-':
d3=d1-d2;
break;
case '*':
d3=d1*d2;
break;
case '/':
d3=d1/d2;
break;
case '%':
d3=d1%d2;
break;
case '^':
d3=Math.pow(d1, d2);
break;
default:
break;
}
st.push(d3);//將操作后的結果入棧
}else{//當是操作數時,就直接進操作數棧
st.push(c);
}
}
return (double) st.pop();
}
/**
* @Describe_求運算符的優先級
*/
private int priority(char c) {
switch (c) {
case '^':
return 3;
case '*':
case '/':
case '%':
return 2;
case '+':
case '-':
return 1;
}
return 0;
}
/** @Describe是否是一個操作符_
*/
import java.util.Scanner;
import org.Stone6762.MStack.imple.LinkStack;
/**
* @author_Stone6762
*/
public class ArithExpEvaluation {
/**
* @Describe_將原始的表達式轉換成一個后綴表達式
* @param expression原始的表達式
* @return與元素表達式相對於的后綴表達式
* @throws Exception
*/
public String conver2Postfix(String expression) throws Exception {
LinkStack st = new LinkStack();// 運算符棧
String postFix = "";// 后綴表達式
for (int i = 0; expression != null && i < expression.length(); i++) {
char c = expression.charAt(i);// 遍歷,如果是操作數,如果是操作符
if (' ' != c) {// 字符不能為空
if (isOpenParenthesis(c)) {// 左括號
// 左括號就入棧
st.push(c);
} else if (isCloseParenthesis(c)) {// 右括號
// 右括號就把所有的操作符出棧知道遇到一個左括號為止,然后將該左括號出棧並丟棄
Character ac = (Character) st.pop();
while (!isOpenParenthesis(ac)) {
postFix += ac.toString();
ac = (Character) st.pop();// 如果取出的是左括號,很顯然就丟棄了
}
} else if (isOperator(c)) {// 操作符
/*
* 如果棧為空,直接進棧。 如果棧非空,則需要將棧頂運算符的優先級和要入棧的運算符的優先級進行比較
* 將棧中比要入棧的運算符優先級高的運算符都出棧,然后將該運算符入棧
*/
if (!st.isEmpty()) { // 如果棧非空,則需要判斷
Character ac = (Character) st.pop();
while (ac != null
&& priority(ac.charValue()) > priority(c)) {
postFix += ac;
ac = (Character) st.pop();
// 因為是先取出來后判斷是,所以如果跳出循環 需要將最后一次取出的操作符壓入棧
}
// 將最后一次取出的優先級低的運算符入棧
if (ac != null) {
st.push(ac);
}
}
// 最后,將該運算符入棧
st.push(c);
} else {// 操作數,直接添加到后綴表達式 中
postFix += c;
}
}
}
// 最后的時候,如果棧非空,則需要棧中的所有的運算符串聯到后綴表達式的末尾
while (!st.isEmpty()) {
postFix += st.pop().toString();
}
return postFix;
}
/**
* @Describe_對后綴表達式進行運算
* @param postFix后綴表達式
* @return計算后的結果
* @throws Exception
*/
public double numberCalculate(String postFix) throws Exception {
LinkStack st = new LinkStack();// 操作數棧
for (int i = 0; i < postFix.length(); i++) {
char c = postFix.charAt(i);
if (isOperator(c)) {
double d2 = Double.valueOf(st.pop().toString());
double d1 = Double.valueOf(st.pop().toString());
double d3 = 0;
switch (c) {
case '+':
d3=d1+d2;
break;
case '-':
d3=d1-d2;
break;
case '*':
d3=d1*d2;
break;
case '/':
d3=d1/d2;
break;
case '%':
d3=d1%d2;
break;
case '^':
d3=Math.pow(d1, d2);
break;
default:
break;
}
st.push(d3);//將操作后的結果入棧
}else{//當是操作數時,就直接進操作數棧
st.push(c);
}
}
return (double) st.pop();
}
/**
* @Describe_求運算符的優先級
*/
private int priority(char c) {
switch (c) {
case '^':
return 3;
case '*':
case '/':
case '%':
return 2;
case '+':
case '-':
return 1;
}
return 0;
}
/** @Describe是否是一個操作符_
*/
private boolean isOperator(char c) {
if ('+' == c || '-' == c || '*' == c || '/' == c || '^' == c
|| '%' == c) {
return true;
}
return false;
}
/** @Describe是否是一個右括號_
*/
private boolean isCloseParenthesis(char c) {
return ')' == c;
}
/**@Describe_判斷是否是一個左括號
*/
private boolean isOpenParenthesis(char c) {
return '(' == c;
}
public static void main(String[] args) throws Exception {
ArithExpEvaluation p=new ArithExpEvaluation();
Scanner scan = new Scanner(
System.in);
System.out.println("請輸入算術表達式: ");
while (scan.hasNext()) {
String str=scan.next();
String postFix=p.conver2Postfix(str);
System.out.println("結果是: "+p.numberCalculate(postFix));
System.out.println();
System.out.println("請輸入算術表達式: ");
}
}
}
if ('+' == c || '-' == c || '*' == c || '/' == c || '^' == c
|| '%' == c) {
return true;
}
return false;
}
/** @Describe是否是一個右括號_
*/
private boolean isCloseParenthesis(char c) {
return ')' == c;
}
/**@Describe_判斷是否是一個左括號
*/
private boolean isOpenParenthesis(char c) {
return '(' == c;
}
public static void main(String[] args) throws Exception {
ArithExpEvaluation p=new ArithExpEvaluation();
Scanner scan = new Scanner(

System.out.println("請輸入算術表達式: ");
while (scan.hasNext()) {
String str=scan.next();
String postFix=p.conver2Postfix(str);
System.out.println("結果是: "+p.numberCalculate(postFix));
System.out.println();
System.out.println("請輸入算術表達式: ");
}
}
}