天天看點

WUSTOJ 1208: 計算整數四則運算表達式的結果(Java) 1208: 計算整數四則運算表達式的結果

1208: 計算整數四則運算表達式的結果

參考資料

資料結構(C語言版)嚴蔚敏 吳偉民 編著————表達式求值

題目

  簡單四則運算。更多内容點選标題。

  1. 保證表達式合法。
  2. 運算符隻包含:加(+),減(-),乘(*),除(/)。
  3. 以等号(=)結束。

提示

  1. 表達式隻包含:數字字元,加,減,乘,除,等号這六種符号。
  2. 測試資料不存在分母為0的情況,代碼中不用考慮。
  3. 全部為int型,不存在浮點型,也就是說:3/2=1,5/2=2。
  4. 切記,雖然題目沒說多組輸入,但是測試資料有很多(我被被坑了)。
  5. 操作數可能不止一位,例如: 10+8=

測試資料(不像OJ的Simple Input跟沒有一樣QAQ)

輸入

-5/2+0+1*3+14=
520=
           

輸出

15
520
           

這兩組資料對了,你可以直接送出了,肯定對。

分析

  這道題目很明顯是在考察棧的運用,不知道棧是什麼的,自己參考其他資料。這裡隻講題目思路。

  有這本書的可以看看書(應該能看懂),沒有的話,我就稍微啰嗦一下。

  四則運算規則不需要我說吧。下面是這道題目的運算關系表:

WUSTOJ 1208: 計算整數四則運算表達式的結果(Java) 1208: 計算整數四則運算表達式的結果

  這裡要用到兩個

棧(Stack)

,分别是

運算數棧(opnd)

運算符棧(optr)

。分别儲存運算符和運算數。代碼聲明如下:

/**
 1. @Field optr 運算符棧
 */
private Stack<Character> optr;
/**
 2. @Field opnd 運算數棧
 */
private Stack<Integer> opnd;
           

  算法思想:

  1. 表達式最後一個字元是 ’=’ ,是以将運算符棧棧底置為 ’=’
  2. 依次讀取表達式中的每個字元,如果是數字字元,則将這個操作數進 opnd 棧,如果是運算符,則和 optr 棧頂運算符比較優先級後進行操作。
  3. 直到計算結束( optr 棧頂和目前字元都為 ’=' 說明計算結束)。

  測試資料 1 運算過程如下:

步驟 optr(運算符棧) opnd(運算數棧) 剩餘字元 主要操作
1 = - 5/2+0+1*3+14= opnd.push(0)
2 = - 5/2+0+1*3+14= optr.push(’-’)
3 = - 5 /2+0+1*3+14= opnd.push(5)
4 = - 0 5 / 2+0+1*3+14= optr.push(’/’)
5 = - / 0 5 2 +0+1*3+14= opnd.push(2)
6 = - / 0 5 2 + 0+1*3+14= opnd.push(calculate(5,’/’,2))
7 = - 0 2 + 0+1*3+14= opnd.push(calculate(0,’-’,2))
8 = -2 + 0+1*3+14= optr.push(’+’)
9 = + -2 +1*3+14= opnd.push(0)
10 = + -2 0 + 1*3+14= opnd.push(calculate(-2,’+’,0))
11 = -2 + 1*3+14= optr.push(’+’)
12 = + -2 1 *3+14= opnd.push(1)
13 = + -2 1 * 3+14= optr.push(’*’)
14 = + * -2 1 3 +14= opnd.push(3)
15 = + * -2 1 3 + 14= opnd.push(calculate(1,’*’,3))
16 = + -2 3 + 14= opnd.push(calculate(-2,’+’,3))
17 = 1 + 14= optr.push(’+’)
18 = + 1 1 4= opnd.push(14)
19 = + 1 14 = opnd.push(calculate(1,’+’,14))
20 = 15 = Output(opnd.peek())

  【備注】手打不易,且看且珍惜。

  【說明】1、左邊是

棧底

,右邊是

棧頂

。2、剩餘字元中的

加粗字元

(也就是最左邊的字元)表示正在讀取的字元。3、

optr.push()

表示進運算符棧;

opnd.push()

表示進運算數棧;

calculate()

表示二進制運算;

opnd.peek()

表示擷取棧頂元素(Java的Stack類自帶方法);

Output()

表示輸出。4、第18步至19步沒看懂的閱讀代碼的

getInt()

方法。

  下圖為課本例題的過程圖:

WUSTOJ 1208: 計算整數四則運算表達式的結果(Java) 1208: 計算整數四則運算表達式的結果

代碼

/**
 * time 268ms
 * @author PengHao
 * @version A2.0
 * @date 2019-04-23 下午10:48:22
 */

import java.util.Scanner;
import java.util.Stack;

public class Main {

	private Scanner sc;
	/**
	 * @Field formal 算式
	 */
	private String formal;
	/**
	 * @Field optr 運算符棧
	 */
	private Stack<Character> optr;
	/**
	 * @Field opnd 運算數棧
	 */
	private Stack<Integer> opnd;
	/**
	 * @Field index 正在讀取的式子中的字元的下标
	 */
	private int index;
	
	public Main() {
		sc = new Scanner(System.in);
		char temp; // 臨時變量
		while (sc.hasNext()) {
			formal = sc.next(); // 式子
			init(); // 初始化
			temp = formal.charAt(index); // 擷取目前字元
			// 隻有目前字元和運算符棧棧頂都是‘=’時,才退出循環,表示計算結束
			while ('=' != temp || '=' != optr.peek()) {
				if (Character.isDigit(temp)) { // 目前字元是數字
					opnd.push(getInt()); // 将目前運算數入棧
				} else { // 目前字元是運算符
					if (0 == index) { // 這個字元是算式的第0個字元
						opnd.push(0); // 将數字0入運算數棧棧頂
					}
					operate(); // 運算操作
				}
				temp = formal.charAt(index); // 擷取算式的目前的字元
			}
			System.out.println(opnd.peek()); // 輸出運算數棧棧頂(即算式結果)
		}
		sc.close();
	}

	/**
	 * Initializes the properties of the class
	 */
	private void init() {
		optr = new Stack<Character>();
		opnd = new Stack<Integer>();
		optr.push('='); // 初始運算符棧有一個‘=’
		index = 0; // 第0個字元
	}

	/**
	 * @return 式子中目前需要輸入的運算數
	 */
	private int getInt() {
		int num = 0, n;
		char temp;
		do {
			// char型轉成int型,并且下标向後移動一位
			n = formal.charAt(index++) - '0';
			num = num * 10 + n; // 轉成運算數
			temp = formal.charAt(index); // 擷取目前字元
		} while (Character.isDigit(temp)); // 目前字元是數字,則屬于同一個運算數
		return num;
	}

	/**
	 * Arithmetic operations
	 */
	private void operate() {
		int num1, num2; // 需要計算的兩個運算數
		char op; // 需要計算的運算符
		char a = optr.peek(); // 運算符棧的棧頂運算符
		char b = formal.charAt(index); // 算式的目前的運算符
		if ('>' == priority(a, b)) { // 棧裡面的運算符優先級較高
			num2 = opnd.pop(); // 先出棧的是第二個運算數
			op = optr.pop(); // 運算符
			num1 = opnd.pop(); // 後出棧的是第一運算數
			opnd.push(calculate(num1, op, num2)); // 運算結果入運算數棧
		} else { // 目前運算符優先級較高
			optr.push(b); // 目前運算符入運算符棧
			index++; // 算式下标後移一位
		}
	}

	/**
	 * @param a 第一個運算符
	 * @param b 第二個運算符
	 * @return > 如果 <b>a</b> 的優先級高于 <b>b</b> 的優先級</br>
	 *         < 如果 <b>a</b> 的優先級低于 <b>b</b> 的優先級
	 */
	private char priority(char a, char b) {
		if ('*' == a || '/' == a) { // a運算符優先級最高
			return '>';
		}
		if ('*' == b || '/' == b) { // b運算符優先級最高
			return '<';
		}
		if ('=' == a) { // a是‘=’,優先級肯定是最低的
			return '<';
		}
		return '>'; // 從左到右運算順序,a優先級高于b(a在b左邊)
	}

	/**
	 * @param num1 第一個運算數
	 * @param op   兩個運算數之間的運算符
	 * @param num2 第二個運算數
	 * @return num1 op num2 的運算結果
	 */
	private int calculate(int num1, char op, int num2) {
		switch (op) {
		case '+':
			return num1 + num2;
		case '-':
			return num1 - num2;
		case '*':
			return num1 * num2;
		case '/':
			return num1 / num2;
		default:
			return 0;
		}
	}

	public static void main(String[] args) {
		new Main();
	}

}
           

寫在最後:

  1. 如需轉載,請于首頁至少注明連結形式的wowpH的部落格這幾個字;
  2. 代碼原創,如需公開引用,不能删除首行注釋(作者,版本号,時間等資訊)。
  3. 如果有疑問歡迎評論留言,盡量解答。

繼續閱讀