1. 程式人生 > >用java編寫棧的經典應用-表示式求值

用java編寫棧的經典應用-表示式求值

     表示式求值是程式設計程式設計中的基本問題也是的經典應用,這裡使用的是書上的方法,也是最廣為流傳的方法“算符優先法

     所謂算符優先就是算術運算中不同運算子有不同的計算優先順序,所以需要使用一個算符優先表來確定計算順序。下面程式碼中有算符優先表,這裡就不寫了

     演算法基本思路:

     準備兩個棧:數值棧用來存放表示式中數值和運算過程中的一些運算結果

                      運算子棧用來存放7種運算子:+    -     *     /     (    )   #    “#”是為了方便編寫

     首先將數值棧設為空棧,運算子棧設“#”作為棧底

     依次讀入表示式的字元,如果是數值字元就使用函式將其轉換為合適的double型數值進入數值棧;如果是運算子字元則和當前運算子棧棧頂通過運算子優先表進行比較並進行相應操作,通過一個while迴圈不斷操作,直至求值完成

具體的方法在程式碼中有詳細的解釋。涉及棧的一些方法這裡沒有寫,如有需求可以看我的前兩篇文章進行了解java實現棧

注意:程式碼中的大部分方法函式為我本人思想,是解題方法中的其中一種方法,供大家參考借鑑,其中有繞彎或者麻煩的地方請指出,謝謝!

import java.util.*;
public class Biaodashi {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		String bds = in.next();//從操作檯獲取表示式
		Jisuan j=new Jisuan(bds);//建立Jisuan類並將表示式輸入
		System.out.println(j.suan());//將結果輸出
	}
}
//棧的元素類
class Node {
	char data;
	double num;
	Node next = null;
	Node pre = null;

	Node(char data) {
		this.data = data;
	}
	Node(double num) {
		this.num = num;
	}


	public char getdata() {
		return data;
	}
	public double getnum() {
		return num;
	}


	public Node getnext() {
		return next;
	}

	public void setnext(Node next) {
		this.next = next;
	}

	public Node getpre() {
		return pre;

	}

	public void setpre(Node pre) {
		this.pre = pre;
	}
}
//棧操作類
class Lianbiao {
	Node hear = null;
	Node tail = null;
	Node prenode = null;
	int a = 0; // 記錄棧長度

	Lianbiao(Node hear) {
		this.hear = hear;
		tail = hear;
		prenode = hear;
	}

	public Node gethear() {
		return hear;

	}

	// 連結串列元素的新增
	public void add(Node node) {
		node.setpre(prenode);
		node.setnext(null);
		prenode.setnext(node);
		prenode = node;
		a++;
	}

	// 元素的輸出
	public Node del() {
		Node sc = null;
		Node n = hear;
		int i = a;
		if (a == 0) {
			System.out.print("錯誤!----棧空!");
		} else {
			while (i > 0) {
				n = n.getnext();
				if (i == 1) {
					prenode = n.getpre();
					n.getpre().setnext(null);
					sc = n;
				}
				i--;
			}
			a--;
		}
		return sc;
	}

	// 遍歷輸出列表(此方法用於測試,不受規則約束,使用棧時避免使用)
	public void bianli() {
		Node n = hear;
		while (n != null) {
			System.out.print(n.getdata() + " ");
			n = n.getnext();
		}
		System.out.println();
	}

	// 遍歷輸出列表(此方法用於測試,不受規則約束,使用棧時避免使用)
    public void bianli1() {
	Node n = hear;
	while (n != null) {
		System.out.print(n.getnum() + " ");
		n = n.getnext();
	}
	System.out.println();
}

}
//表示式計算類
class Jisuan {
	int jieshu = 0;//用於判斷運算是否結束
	int n = 0;     //用於讀取表示式,指向當前使用字元
	char[] c;  
	//計算類的建構函式
	Jisuan(String bds) {
		bds=bds+"#";//為了便於計算在表示式字串後面加#
		c = bds.toCharArray();//將String型字串轉換為char型陣列
	}
	// 建立字元棧
	Node hear = new Node(' ');//為了方便棧操作,預設有一個棧底,使用棧時可以忽略
	Lianbiao zhifu = new Lianbiao(hear);//建立棧,用來存放運算子
	// 建立數值棧
	Node hear1 = new Node('0');
	Lianbiao shuzhi=new Lianbiao(hear1);//建立棧,用來存放數值
	//獲取運算時運算優先類
public char youxian(char a,char b){
		int i=0,j=0;
		//建立一個char型二維陣列用於存放運算優先表
		char[][] pri = { // 運算子優先表
				// +    -    *    /    (         )         #      橫向為表示式當前運算子
		/* + */	{ '>', '>', '<', '<', '<', '>', '>' }, 
		/* - */	{ '>', '>', '<', '<', '<', '>', '>' },
		/* * */	{ '>', '>', '>', '>', '<', '>', '>' },
		/* / */	{ '>', '>', '>', '>', '<', '>', '>' },
		/*(    */	{ '<', '<', '<', '<', '<', '=', ' ' }, 
		/* ) */	{ '>', '>', '>', '>', ' ', '>', '>' },
		/* # */	{ '<', '<', '<', '<', '<', ' ', 's' }, };
//縱向為運算子棧棧頂的運算子
		if(a=='+'){i=0;}
		if(a=='-'){i=1;}
		if(a=='*'){i=2;}
		if(a=='/'){i=3;}
		if(a=='('){i=4;}
		if(a==')'){i=5;}
		if(a=='#'){i=6;}
		if(b=='+'){j=0;}
		if(b=='-'){j=1;}
		if(b=='*'){j=2;}
		if(b=='/'){j=3;}
		if(b=='('){j=4;}
		if(b==')'){j=5;}
		if(b=='#'){j=6;}	
		return pri[i][j];
	}
//運算類
public double js(double a,char c,double b){
	double jieguo=0;
	if(c=='+'){jieguo=a+b;}
	if(c=='-'){jieguo=a-b;}
	if(c=='*'){jieguo=a*b;}
	if(c=='/'){jieguo=a/b;}
	return jieguo;
	
}
//讀取表示式中數值,因為表示式是以char型陣列存放表示式,通過此函式轉換為double型
public double duqushuzhi(char[] c){
	String s="";//建立一個String型數值s用來存放char型數值
	//表示式中可能存在多位的數值,所以通過一個迴圈將其轉變為一個double型數值
	while(c[n] != '+' && c[n] != '-' && c[n] != '*' && c[n] != '/' 
			&& c[n] != '(' && c[n] != ')' && c[n] != '#'){//如果不是指定運算子,那麼就是數值
		s=s+c[n];n++;
	}
	double d=Double.valueOf(s);//將String型數值轉換為double型
	return d;
}
//計算    ***表示式求值核心內容
public double suan(){
	double d=0;//存放最終結果
	double qian=0,hou=0;
	zhifu.add(new Node('#'));
	while(jieshu==0)
	{
		
		if (c[n] != '+' && c[n] != '-' && c[n] != '*' && c[n] != '/' 
				&& c[n] != '(' && c[n] != ')' && c[n] != '#') //不是運算子則就是數值,進數值棧
		{		shuzhi.add(new Node(duqushuzhi(c)));}//進棧時呼叫上方的方法得到double型數值
		else{switch(youxian(zhifu.prenode.getdata(),c[n])){//呼叫上方方法 並輸入棧頂運算子和當前表示式運算子比較
		
		case '<'://棧頂元素優先順序低
			zhifu.add(new Node(c[n]));//將當前表示式運算子入棧作為新的棧頂
			n++;                      //n++   指向下一個字元 繼續迴圈
			break;
		case'='://脫括號進入下一位元組          出現'='時一定是棧頂運算子為'('  表示式當前運算子為')'
			zhifu.del();        //消除棧頂運算子'('    繼續迴圈
			n++;
			break;
		case'>':              //退棧並將運算結果入棧
			hou=shuzhi.del().getnum();  //取出數值棧當前棧頂 作為運算數
			qian=shuzhi.del().getnum(); //取出數值棧當前棧頂 作為第二個運算數   注意:結合上一句一共從棧中去兩個數值
			shuzhi.add(new Node(js(qian,zhifu.del().getdata(),hou)));
			//取出運算子棧棧頂並和兩個運算子一起輸入運算函式中計算結果並將結果入數值棧    繼續迴圈
			break;
		case's'://當出現's'時,運算子棧已經沒有除'#'以外的運算子,計算完畢
			d=shuzhi.del().getnum();//此時數值棧中只有一個數值就是最終結果
			jieshu=1;              //停止迴圈
		}
			
		}
	}
	return d;    //返回最後結果
	
}

}

*原創作品,轉載請表明出處。有建議或者問題歡迎聯絡我,QQ1595787997