大二的時候的一個小項目---實現四則運算的邏輯分析實現(小型編譯器)

輸入四則運算表達式,可以計算得到結果,可以輸入小括號。

利用了棧和隊列的數據結構。

使用了運算式的中綴表達式和後綴表達式的概念。中綴表達式利於人的理解,後綴表達式利於計算機的理解。

前綴表達式(Prefix Notation)是指將運算符寫在前面操作數寫在後面的不包含括號的表達式,而且爲了紀念其發明者波蘭數學家Jan Lukasiewicz所以前綴表達式也叫做“波蘭表達式”。比如- 1 + 2 3

後綴表達式(Postfix Notation)與之相反,是指運算符寫在操作數後面的不含括號的算術表達式,也叫做逆波蘭表達式。比如1 2 3 + -

中綴表達式(Infix Notation)就是常用的將操作符放在操作數中間的算術表達式。前綴表達式和後綴表達式相對於中綴表達式最大的不同就是去掉了表示運算優先級的括號,比如1-2+3

關於這些表達式的知識:可以參看http://www.cnblogs.com/MichaelYin/archive/2012/05/02/2479248.html

遇到的問題:

類型轉換的問題

異常處理還沒有做好。

在強制轉換之前,應該先用instanceof判斷下待轉換對象是否是引用類型的類型或者是其派生類,否則會報這個錯誤。
以前有一個誤解,就是在做這個小項目的時候,就是說感覺所有類都是Object的子類,當然就可以任意轉換。
這是錯誤的,打比方說,Dog是Anaimal的子類,Cat也是,他們與父類之間當然可以轉換,但是Dog和Cat之間就是不行的。

細節問題


package com.my.calculator;

public class Number {
	private double number = 0.0;

	public Number(double number) {
		this.number = number;
	}

	public Number(String number) {
		this.number = Double.parseDouble(number);
		//this.number = Double.valueOf(number);
	}

	public double getNumber() {
		return number;
	}

	public String toString() {
		return String.valueOf(number);
	}
}


package com.my.calculator;

public class Operator {
	//之所以要將這個String定義成static的形式。
	//是因爲後面有一個static方法要用到。
	private static final String OPERATORS ="+-/*^()";
	private final int[] LEVEL = {1,1,2,2,3,0,9};
	private String operator;
	
	public String getOperator(){
		return this.operator;
	}
	public Operator(String operator){
		if(OPERATORS.indexOf(operator)>=0){
			this.operator = operator;
		}else{
			System.out.println("輸入的操作符非法");
		}
	}
	//判斷是不是左括號,在中綴變後綴的時候需要用到
	public boolean isLeftBracker(){
		return operator.equals("(");
	}
	//返回操作碼的優先級
	public int order(){
		int id = OPERATORS.indexOf(operator); 
		return LEVEL[id];
	}
	//判斷一個操作符是否是有效
	public static boolean isValidOp(char op){
		return (OPERATORS.indexOf(op)>=0);
	}
	public boolean isRightBracker() {
		return operator.equals(")");
	}
	
	public Number evalute(double num1,double num2){
		if(operator.equals("-")){
			return new Number(num1-num2);
		}else if(operator.equals("+")){
			return new Number(num1+num2);
		}else if(operator.equals("*")){
			return new Number(num1*num2);
		}else if(operator.equals("/")){
			return new Number(num1/num2);
		}else if(operator.equals("^")){
			return new Number(Math.pow(num1, num2));
		}
		return null;
	}
}


package com.my.calculator;
class Node{
	protected Object data;
	protected Node next;
	protected Node(){
		data = null;
		next = null;
	}
	
	protected Node(Object data){
		this.data = data;
		this.next = null;
	}
}

public class Queue {
	private Node head;
	private Node tail;
	private int size = 0;
	public Queue(){
		head = tail = null;
	}
	//向隊列尾部插入數據
	public void add(Object obj){
		Node node = new Node(obj);
		if(head == null){
			head = node;
		}
		else{
			tail.next = node;
			this.size ++;
		}
		tail = node;
	}
	
	//從隊列頭部刪除數據並且返回
	public Object remove(){
		Object data = head.data;
		head = head.next;
		this.size --;
		if(head == null){
			tail = null;
		}
		return data;
	}
	
	//查看隊列頭部數據但是不刪除
    public Object peek(){
    	if(head == null){
    		return null;
    	}else{
    		return head.data;
    	}
    }
    
    public boolean isEmpty(){
    	return this.size < 0;
    }
    
    public int size(){
    	return this.size;
    }
	public static void main(String args[]){
		Node node = new Node();
	}
}

package com.my.calculator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

public class Calculator {

	// 得到中綴表達式
	public Queue stringToInfix(String input) {
		Queue Q = new Queue();
		String str = new String("");
		for (int i = 0; i < input.length(); i++) {
			/*
			 * char c = input.charAt(i); Q.add(c); System.out.println(c + " " +
			 * Q.size());
			 */

			char c = input.charAt(i);
			if (Operator.isValidOp(c)) {
				str += c;
				Q.add(new Operator(str.trim()));
				str = new String("");
			} else {
				str += c;
				Q.add(new Number(str.trim()));
				str = new String("");
			}

		}
		return Q;
	}
    /*
	中綴序列轉化爲後綴序列的方法:
	1:遇到數字,加入後綴對壘
	2:遇到操作符,判斷是不是左括號,是的話壓入棧,不是的話判斷是不是右括號,是的話將棧中的數據依次彈出直到左括號(去掉左括號),
	如果不是以上兩種情況,首先判斷棧是否爲空,爲空直接壓站,不爲空判斷是否棧頂的操作符的優先級與這個操作符的優先級之間的關係*/
	// 從中綴表達式當中獲得後綴表達式
	public Queue infixToPostfix(Queue infix) throws ClassCastException {
		Stack<Operator> s = new Stack<Operator>();
		Queue Q = new Queue();
		while (!infix.isEmpty()) {
			Object c = infix.remove();
			// 如果是一個操作數
			if (c instanceof Number) {
				Q.add(c);
			} else {
				Operator op = (Operator) c;
				if (op.isLeftBracker())
					s.push(op);
				else if (op.isRightBracker()) {
					while (!(s.peek().isLeftBracker())) {
						Q.add(s.pop());
					}
					s.pop();// 清除掉左括號
				} else if (s.isEmpty()) {
					s.push(op);
				} else if (s.peek().order() < op.order()) {
					s.push(op);
				} else {
					while ((!s.empty()) && s.peek().order() >= op.order()) {
						Q.add(s.pop());
					}
					s.push(op);
				}
			}
		}

		while (!s.empty()) {
			Q.add(s.pop());
		}

		return Q;
	}

	// 計算後綴表達式
	public double evalutePostFix(Queue postfix) {
		Stack<Number> numbers = new Stack<Number>();
		while (!postfix.isEmpty()) {
			Object ob = postfix.remove();
			if (ob instanceof Operator) {
				Number num1 = numbers.pop();
				Number num2 = numbers.pop();
				Operator op = (Operator) ob;
				System.out.print(op.getOperator());
				Number temp = op.evalute(num1.getNumber(), num2.getNumber());
				System.out.print(temp.getNumber());
				numbers.push(temp);
				System.out.println(num1.getNumber()+" "+num2.getNumber()+" "+op.getOperator()+" "+ numbers.peek().getNumber());
			} else {
				numbers.push((Number) ob);
				System.out.println(numbers.peek().getNumber());
			}
		}
		Number answer = numbers.pop();
		if (numbers.isEmpty()) {
			return answer.getNumber();
		} else {
			System.out.println("錯誤的表達式");
			return 0.000;
		}
	}

	public static void main(String args[]) throws ClassCastException {
		String info = "請輸入運算式:(q to quit)";
		Calculator cal = new Calculator();
		/*
		 * Queue queue = cal.stringToInfix(input);
		 * 
		 * System.out.println(queue.size()); while (!queue.isEmpty()) {
		 * System.out.println(queue.remove()); }
		 * 
		 * Queue postfix = postfix = cal.infixToPostfix(queue);
		 * 
		 * System.out.println(postfix.size()); while (!postfix.isEmpty()) { if
		 * (postfix.peek() instanceof Number)
		 * System.out.println(postfix.remove()); else
		 * System.out.println(((Operator) postfix.remove()).getOperator()); }
		 */
		BufferedReader buff = new BufferedReader(new InputStreamReader(
				System.in));
		try {
			System.out.println(info);
			String input = buff.readLine();
			while (!input.equalsIgnoreCase("q")) {
				if (!input.equals("")) {
					Queue infix = cal.stringToInfix(input);
					Queue postfix = cal.infixToPostfix(infix);
					/*System.out.println(postfix.size());
					while (!postfix.isEmpty()) {
						if (postfix.peek() instanceof Number)
							System.out.println(postfix.remove());
						else
							System.out.println(((Operator) postfix.remove())
									.getOperator());
					}*/
					double ans = cal.evalutePostFix(postfix);
					System.out.println(ans);
				}
				System.out.println(info);
				input = buff.readLine();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章