1. 程式人生 > >c2java 第5篇 棧和中綴表示式的直接計算

c2java 第5篇 棧和中綴表示式的直接計算

中綴表示式一般是先轉換為字尾表示式,然後再計算的,其實我們可以邊轉換邊計算。

/*Infix.java
使用兩個棧直接求解中綴表示式,一個棧儲存運算子S,一個棧儲存運算元D。
例子:
a+b*c
  D:a,b S:+
    D:a,b,c S:+,*
    D:a,bc  S:+ <-- 每次取一個運算子,彈兩個運算元
    D:a+bc  S:

a*b/c+d
  D: a,b S:*
   D: a*b S:/ <-- 清空優先順序大於等於除號的運算子
     D:a*b/c S:+
      D:a*b/c+d S:
a^b^c
  D:a,b S:^
    D:a,b,c S:^,^ <-- 清空棧優先順序大於等於冪號掃描優先順序的運算子
    D:a,b^c S:^
    D:a^b^c S:

a*(b+c)
  D:a  S:*(
    D:a,b S:*(+
	  D:a,b,c S:*(+)
      D:a,b+c S:* <-- 清空操作符直到(
      D:a*(b+c) S:

這幾種情形,通過賦予運算子適當的優先順序,可統一為:
  清空棧優先順序大於等於掃描優先順序的運算子 (R0)

這裡只是為了說明棧的應用,因此簡單假設運算元是一位數字,並且沒有空格,
如果擴充套件成BigDecimal應該不困難。
中綴表示式的計算規則,從左到右掃描一遍,在掃描過程中:
  R1 如果遇到數字,則壓入運算元棧D;
  R2 如果遇到操作符,則根據R0彈出S中的操作符;
  R3 每彈出一個操作符,就彈出D中兩個運算元,並把結果壓入D。

掃描結束時,可能S不為空,按規則R3。最終D中僅有的一個是結果,S 應該為空。

author: ludi 2014.04
*/
import java.util.Stack;
public class Infix
{
	public static int eval(int a, int b, char op)
	{
		  int ret = 0;
			switch(op){
				case '+': ret = a + b; break; 
				case '-': ret = a - b; break;
				case '*': ret = a * b; break;
				case '/': ret = a / b; break;
				case '%': ret = a % b; break;
				case '^': {
					ret = 1;
					while(b-- > 0){
						ret *= a;
					}			
				}break;
				default: System.out.println("error op " + op); break;
			}
		 return ret;
	  }

	public static int evaluate(String infix)
	{
		Stack<Integer> d = new Stack<Integer>();
		Stack<Symbol> s = new Stack<Symbol>();
		int i, a, b;
		char ch;
		Symbol op, op2;

		for(i = 0; i < infix.length(); ++i){
			ch = infix.charAt(i);
			if (Character.isDigit(ch)){
				d.push(ch - '0');
			}else {
				op = new Symbol(ch);
				while(!s.empty() && (s.peek().compareTo(op) >= 0)){
					op2 = s.pop();
					b = d.pop();
					a = d.pop();
					d.push(eval(a, b,op2.op));
				}
				if(ch == ')'){
					s.pop(); /*彈出'('*/
				}else s.push(op);
			}
		}

		while(!s.empty()){
			op2 = s.pop();
			b = d.pop();
			a = d.pop();
			d.push(eval(a, b, op2.op));
		}

		System.out.printf("%s = %d d.size %d s.size %d%n", infix, d.peek(), d.size(), s.size());
		return d.pop();
	}
	
	public static void main(String[] arg)
	{
		evaluate("1+2*3");
		evaluate("2*(3+4)");
		evaluate("2*3/2+1");
		evaluate("2^3^2");
		evaluate("(2^3)^2");
		evaluate("(2^3)^2+2^3^2+2*3/2+1+2*(3+4)");
		evaluate("2^(2*(3+4))");
	}
}

 class Symbol implements Comparable<Symbol>
{
      char op; 
      int inputPrec; /*正在被掃描的操作符的優先順序*/
      int stackPrec; /*棧優先順序:值越小停留在棧中時間越長*/ 

      public Symbol (char ch){
         op = ch; 
         switch(op){
            case '+':
            case '-':inputPrec = stackPrec = 1;
                break;

            case '*':
            case '%':
            case '/':   inputPrec = 2;
                     	stackPrec = 2;
                     	break;

            case '^':
					inputPrec = 4;
                    stackPrec = 3; /*右結合的操作符掃描大於棧優先順序*/
                    break;

            case '(':   
					inputPrec = 5; 
                    stackPrec = -1; /*最高的掃描優先順序,最低的棧優先順序*/
                    break;

            case ')':   
					inputPrec = 0;
                    stackPrec = 0;
                    break;
         }
      }

      public int compareTo(Symbol item)
      {
         int result;
         if (stackPrec < item.inputPrec)
            result = -1;
         else if (stackPrec == item.inputPrec)
            result = 0;
         else
            result = 1;

         return result;
      }

      public char getOp()
      { return op; }
}

/*
[email protected]
~/java $ javac -encoding UTF-8 Infix.java && java Infix 1+2*3 = 7 d.size 1 s.size 0 2*(3+4) = 14 d.size 1 s.size 0 2*3/2+1 = 4 d.size 1 s.size 0 2^3^2 = 512 d.size 1 s.size 0 (2^3)^2 = 64 d.size 1 s.size 0 (2^3)^2+2^3^2+2*3/2+1+2*(3+4) = 594 d.size 1 s.size 0 2^(2*(3+4)) = 16384 d.size 1 s.size 0
[email protected]
~/java */

這裡面為了簡明起見,沒有做錯誤處理。

很好奇編譯器是怎麼計算常量表達式的,不知道是不是這樣子呢。

附:

一些與棧有關的有意思的話題:

相關推薦

c2java 5 中綴表示式直接計算

中綴表示式一般是先轉換為字尾表示式,然後再計算的,其實我們可以邊轉換邊計算。 /*Infix.java 使用兩個棧直接求解中綴表示式,一個棧儲存運算子S,一個棧儲存運算元D。 例子: a+b*c D:a,b S:+ D:a,b,c S:+,* D:a,b

5章 迴圈關係表示式筆記續

c風格字串中的strcmp()函式可以接受兩個字串地址作為引數,這意味著引數可以是指標、字串常量或字元數字組名。如果兩個字串相同,該函式將返回零;如果第一個字串按字母順序排在第二個字串之前,則strcmp()將返回一個負數值,否則返回一個正數值。 while迴圈 它只有測試條件和迴圈體

字首表示式、字尾表示式中綴表示式計算(double型)

有關中綴表示式的計算以及中綴表示式與字首表示式、字尾表示式之間的轉換   後續文章會繼續給出 這裡只講字首表示式與字尾表示式計算的實現方法 字首表示式 計算方法:   將得到的字串處理為

Python學習【5】:數據類型變量總結

style 不可變 nbsp 重新 class 數據 發現 舉例 convert 字符串,數字,列表,元組,字典 可變不可變 1.可變:列表 如: p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; col

Struts2三天:Struts2的值OGNL表示式

目錄 1.OGNL 1.1OGNL概述 1.1.1什麼是OCNL 1.1.2為什麼學習OGNL 1.1.3OGNL使用的要素 1.2OGNL的Java環境入門(瞭解) 1.2.1訪問物件的方法 1.2.2訪問物件的靜態方法 1.2.3獲得root中的資料

c2java 7 圖的連通分量,關節點

圖的連通分量,關節點和橋 ==== 對於有向圖,我們稱其一個子圖是強連通分量,是指任意兩點u,v, 都有兩條路徑u到v和v到u。對於連通無向圖,我門稱其一個子圖是雙連通分量,是指任意兩點u,v,存在一個圈包含u,v。與無向圖相關聯的還有關節點x,是指去掉x,圖不連通;橋(u

5-JAVA面向對象Ⅰ

java 面向對象 計算機語言 種類 現實生活 第5篇-JAVA面向對象Ⅰ每篇一句 :面向對象面向君,不負代碼不負卿初學心得: 代碼虐我千百遍,我待代碼如初戀(筆者:JEEP/711)[JAVA筆記 | 時間:2017-04-03| JAVA面向對象 Ⅰ]1.JAVA作為一種面向對象語言,

數據結構——與遞歸

分解 是什麽 運行時 使用 執行過程 非遞歸算法 long 應該 char 棧還有一個重要應用是在程序設計中實現遞歸。遞歸是計算機 科學和數學中一種解決問題的及其重要的方法。在數據結構中,可以用它來設計簡單。易於理解的算法,特別是在一些具有遞歸定義的結構上設計算法。 遞歸的

python基礎5 python基礎補充內容

兩個 其他 plain pac 3.5 表示 post IT 增強 知識內容: 1.python代碼編寫規範 2.模塊導入與使用 3.python文件名 4.python腳本的"__name__"屬性 5.python之禪 一、python代碼編寫規範 1、縮進 p

python學習[十三] 條件循環

one res mds this 沒有 case語句 Suite 部分 字典 python學習[第十三篇] 條件和循環 if語句 單一if 語句 if語句有三個部分構成,關鍵字if本身,判斷結果真假的條件表達式,以及表達式為真或非0是執行的代碼 if expression:

開啟運維之路之 5 ——Redis介紹、安裝、管理

Redis:Redis是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。Redis百度百科介紹 瞭解下NoSQL (Not noly SQL)不僅僅是SQL,Redis就屬於非關係型資料庫,Mysql ,orac

5】模組

一、time模組 表示時間的三種方式: 時間戳:數字(計算機能認識的) 時間字串:t = '2012-12-12' 結構化時間:time.struct_time(tm_year=2018, tm_mon=11, tm_mday=6, tm_hour=15, tm_min=19, tm_sec=9, t

多執行緒設計模式: - ThreadLocalActive Object模式

一,ThreadLocal         Java 中的 ThreadLocal 類給多執行緒程式設計提供了一種可以讓每個執行緒具有自己獨立空間的機制,在這個空間記憶體儲的資料是執行緒特有的,不對外共享。  &nb

多線程設計模式: - ThreadLocalActive Object模式

note active 計算 news 設計模式 簡化 Language return 通過 一,ThreadLocal Java 中的 ThreadLocal 類給多線程編程提供了一種可以讓每個線程具有自己獨立空間的機制,在這個空間內存儲的數據是線程特有的

《C++ Primer Plus》學習筆記——五章 迴圈關係表示式(一)

本章內容: for迴圈和while迴圈 表示式和語句 運算子組合 複合語句 逗號運算子以及關係運算符 typedef工具 字元輸入方法get() 檔案尾條件 巢狀迴圈和二維陣列 計算機除了儲存資料外,還可以做很多其他工作。可以對資料進

5】TypeScript塊module的案例程式碼詳解

https://blog.csdn.net/jilongliang/article/details/47355263 6.1分多個ts檔案實現module塊 Validation.ts程式碼 module Validation{     

5 Java常用類

API:(Application Programming Interface,應用程式程式設計介面)是一些預先定義的函式,目的是提供應用程式與開發人員基於某軟體或硬體的以訪問一組例程的能力,而又無需訪問原始碼,或理解內部工作機制的細節。   --< java.lang&nbs

完美C++5版中文英文原版《AbsoluteC++5th》完整帶目錄超清晰

連結:https://pan.baidu.com/s/1tRQ6amOl_STtKeCKh1s16Q 完美C++中文版、英文原版《Absolute C++5th》和書作者力推的《Problem Solving with C++ 9th》 前兩本可做學習C++入門參考書籍,排版清晰,很人性化,內容總結精煉。第

Oracle Database 12c DBA文官手冊(8版)——5章 開發實現應用程式(續)

5.2、資源管理5.2.1、實現資料庫資源管理需要建立資源計劃、資源消費者組和資源計劃指令。使用資源管理器命令前須建立“未決區域”。針對會話啟用ADMINISTRATOR_RESOURCE_MAANAGER系統許可權將使用者賦給資源消費者組建立資源計劃指令分配相關資源1 切換消費者組2 使用SQL配置檔案5.

Oracle Database 12c DBA文官手冊(8版)——5章 開發實現應用程式

1 調整設計:最佳實踐         1.1做盡可能 少的工作             應該簡化應用