大二的时候的一个小项目---实现四则运算的逻辑分析实现(小型编译器)

输入四则运算表达式,可以计算得到结果,可以输入小括号。

利用了栈和队列的数据结构。

使用了运算式的中缀表达式和后缀表达式的概念。中缀表达式利于人的理解,后缀表达式利于计算机的理解。

前缀表达式(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();
		}
	}
}


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