`
mabusyao
  • 浏览: 253340 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

java写的四则运算器

阅读更多

本打算做一个从RE到NFA的转换器,思路已经理清了,但是在动手做的时候,遇到了很多问题,有些技术难点都遗忘了,包括如何定义闭包,如何利用递归来实现。

 

于是回头重新拾起这些技术,边学边思考,做了个四则运算器练练手,为着那个大目标做准备。

 

 

基本的思路是这样的:

 

根据输入的四则运算表达式,生成一棵二叉树,树的根节点是操作符,而子树可能是叶子节点,即数字。也可能是另一个运算表达式。生成树的规则是,对每一个节点产生一个相应的type值,type值越大,就在树的越靠上节点。基本原则是: 数字(10) < 乘除运算(20) < 加减运算(30)。

 

括号被当做是一种特殊的符号,并不会在二叉树上显示出来,相应的,它会影响到在括号内出现符号的type值,每嵌套一层括号,就会将type值减少100, 这样确保了括号内的内容在树的最底层。

 

当二叉树构造好了之后,利用递归,将左树的计算结果与右树的结果,根据根操作符计算出结果。

 

举例:10 

生成树只有一个节点,同时也是根节点,返回值便是根节点值。

 

举例: 10 + 2

首先生成根节点为10,但当读入+时,+的type值比10高,因此上移,并成为新的跟节点,最后加入2,因为2比+type值小,因此作为右子节点。

 

举例: 10 + 2 * 5

当读入*时,*的type值比2大,因此上移,同时又比+的type值小,因此就在+与2之间插入新的节点。

 

举例: 10 + 2 *(2 + 3)

当读入(时,后面所产生的所有Node的type值会相应的-100, 因此括号内的+的type值就会比外面的*小,但是仍然比括号内的数字大,这样保证了在树中,2+3会先执行。当读入)时,offset清零。

 

 

public class Main {

	public static void main(String[] args) {
		String exp = "(10 + 15) * 3 - 20 * 6 /5 - (8 + 14(2- 1))2 + 11(12 - 11)5";
		//String exp = "12";
		Main main = new Main();
		Main.index = 0;
		
		char[] input = main.prepare(exp.toCharArray());
		
		System.out.println(main.cal(input));
	}
	
	/**
	 * Actual calculate method.
	 * @param exp
	 * @return
	 */
	public int cal(char[] exp) {
		Node root = buildTree(exp);
		
		return calculate(root);
	}
	
	/**
	 * Prepare the exp, remove empty space or \n.
	 * Also the method will add losing * in below cases:
	 * 10(3-1)   ---->   10*(3-1)
	 * (3-1)10   ---->   (3-1)*10
	 * 
	 * @param exp
	 * @return
	 */
	public char[] prepare(char[] exp) {
		char[] worklist = new char[exp.length];

		int j = 0;
		for (int i = 0; i < exp.length; i++) {
			char c = exp[i];

			if (c == ' ' || c == '\n') {
				continue;
			} else {
				if (c == '(') { // Handle the abbreviated * for (
					if(j == 0 || isCalculator(worklist[j - 1])) {
						//Do nothing.
					} else {
						worklist[j++] = '*';
					}

					
					worklist[j++] = c;
				} else if (c == ')') {// Handle the abbreviated * for )
					worklist[j++] = c;
					
					while((i == exp.length - 1) || (exp[++i] == ' ')) {
						//Do nothing.
					}
					
					if(isCalculator(exp[i]) || exp[i] == ')') {
						//Do nothing.
					} else {
						worklist[j++] = '*';
					}
					
					i--;
				} else {
					worklist[j++] = c;
				}
			}
		}
		
		char[] result = new char[j];
		
		System.arraycopy(worklist, 0, result, 0, j);
		
		return result;
	}
	
	/**
	 * Check if c is a calculator or not.
	 * @param c
	 * @return
	 */
	private boolean isCalculator(char c) {
		if(c == '+' || c == '-' || c == '*' || c == '/') {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Calculate the tree.
	 * 
	 * @param node
	 * @return
	 */
	private int calculate(Node node) {
		if(node.isLeaf()) return Integer.parseInt(node.value);
		
		if(node.value.equals("+")) {
			return calculate(node.leftChild) + calculate(node.rightChild);
		} else if(node.value.equals("-")) {
			return calculate(node.leftChild) - calculate(node.rightChild);
		} else if(node.value.equals("*")) {
			return calculate(node.leftChild) * calculate(node.rightChild);
		}else {
			return calculate(node.leftChild) / calculate(node.rightChild);
		}
	}
	
	/**
	 * Build a tree like this:
	 * 
	 * 10 * (3 + 5)
	 *  * ------ 10
	 *    -
	 *    ------ +
	 *           -
	 *           ------- 3
	 *           ------- 5 
	 * @param exp
	 * @return
	 */
	private Node buildTree(char[] exp) {
		Node root = null;
		Node working = null;
		
		while(true) {
			Node node = readNext(exp);
			
			if(node == null) break;
			
			if(root == null) {
				root = node;
				working = node;
				
				continue;
			}
			
			if(node.type > working.type) {
				
				Node parent = working.parent;
				boolean isLeft = false;
				while(parent != null && node.type >= parent.type) {
					isLeft = parent.isLeft;
					working = parent;
					parent = parent.parent;
				}
				
				if(parent == null) {
					working.parent = node;
					node.leftChild = working;
					working.isLeft = true;
					
					root = node;
				} else {
					Node tmp = isLeft ? parent.leftChild : parent.rightChild;
					
					if(isLeft) {
						parent.leftChild = node;
					} else {
						parent.rightChild = node;
					}
					node.isLeft = isLeft;
					node.parent = parent;
					tmp.parent = node;
					node.leftChild = tmp;
					tmp.isLeft = true;
				}
			} else {
				working.rightChild = node;
				node.isLeft = false;
				node.parent = working;
			}

			working = node;
		}
		
		return root;
	}
	
	private static int index = 0;
	// Read the next node, it possible to be a number, a calculator or just space.
	private Node readNext(char[] exp) {
		
		if(index >= exp.length) return null;
		
		Node node = new Node();
		
		char c = exp[index++];
		
		if(Character.isDigit(c)) {
			node.type = Node.NUMBER + offset;
			StringBuffer sb = new StringBuffer();
			sb.append(c);
			for(; index < exp.length; index++) {
				char tmp = exp[index];
				if(Character.isDigit(tmp)) {
					sb.append(tmp);
				} else {
					break;
				}
			}
			
			node.value = sb.toString();
		} else if (c == '*' || c == '/') {
			node.type = Node.MUL_DEL + offset;
			node.value = Character.toString(c);
		}else if (c == '+' || c == '-') {
			node.type = Node.PLUS_MINUS + offset;
			node.value = Character.toString(c);
		} else if(c == '(') {
			increaseOffset();
			return readNext(exp);
		}else if(c == ')') {
			decreaseOffset();
			return readNext(exp);
		}
		
		return node;
	}
	
	
	// Every type in the embrace will have to add a offset as their type.
	private static int offset = 0;
	public static void increaseOffset() {
		offset = offset - 100;
	}
	
	public static void decreaseOffset() {
		offset = offset + 100;
	}
	

	/**
	 * Helping class.
	 *
	 */
	class Node {
		private int type = 10;
		
		private Node parent = null;
		
		private Node leftChild = null;
		
		private Node rightChild = null;
		
		private boolean isLeft = false;
		
		private String value = null;
		
		public Node() {
			
		}
		
		public static final int NUMBER = 10;
		public static final int MUL_DEL = 20;
		public static final int PLUS_MINUS = 30;

		public static final int EMBRACE = -100;
		
		public boolean isLeaf() {
			if(leftChild == null && rightChild == null) {
				return true;
			}
			
			return false;
		}

		public int getType() {
			return type;
		}

		public void setType(int type) {
			this.type = type;
		}

		public Node getParent() {
			return parent;
		}

		public void setParent(Node parent) {
			this.parent = parent;
		}

		public Node getLeftChild() {
			return leftChild;
		}

		public void setLeftChild(Node leftChild) {
			this.leftChild = leftChild;
		}

		public Node getRightChild() {
			return rightChild;
		}

		public void setRightChild(Node rightChild) {
			this.rightChild = rightChild;
		}

		public boolean isLeft() {
			return isLeft;
		}

		public void setLeft(boolean isLeft) {
			this.isLeft = isLeft;
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}
	}
}
 

 

分享到:
评论
1 楼 mabusyao 2011-08-21  
今天看到另一位仁兄用栈的方式实现,想法也是不错:
http://justsee.iteye.com/blog/1125174

相关推荐

    java.四则运算器

    在Java编程语言中,四则运算器是一种程序,它能够执行基本的数学操作,包括加法(+)、减法(-)、乘法(*)和除法(/)。这类程序通常用于教学目的,以帮助初学者理解如何在Java中处理数字和运算。在这个“java.四...

    用Java编写的四则运算器

    本项目是一个基于Java的四则运算器,适用于初学者理解和实践Java的基础语法和控制流程。四则运算器是计算机科学中最基本的计算工具,能够进行加法、减法、乘法和除法操作。 首先,`Calc.java` 文件是这个项目的源...

    四则运算器

    用java开发四则运算器,解压后只接运行即可。 带有原码和注释。图形界面。

    Java四则运算器

    该程序是基于GUI设计的一款小型四则运算器,java爱好者参考参考!!

    基于Java实现四则运算题目生成程序.zip

    通过以上步骤,我们可以构建一个功能完备的四则运算题目生成器,它不仅能满足基本的运算题生成,还能根据需求进行扩展,提升用户体验。对于学习Java编程和理解面向对象设计原则的学生来说,这是一个很好的实践项目。

    小学生四则运算器(JAVA)

    用JAVA简单实现了一个小学生运算器,包括加减乘除四种运算。

    基于Java实现自动生成四则运算【100012409】

    自动生成 10 道 100 以内的 2 个操作数的四则运算算式(+ - * /),要求运算结果也在 100 以内,把运算式存入“result.txt”文件中。题目数量、数字范围、操作数和运算规则是可控的。 使用-n 参数控制生成题目的个数...

    java 四则运算计算器

    ### Java四则运算计算器知识点详解 #### 一、项目概述 **标题与描述解析:**“Java四则运算计算器”是一款基于Java语言开发的计算器应用,能够执行加、减、乘、除等基本算术运算,并支持混合运算,具备友好的用户...

    Java图形界面小学生整数四则运算练习软件

    使用图形用户界面编写一个小学生整数四则运算练习软件。程序启动后,用户输入用户名,然后选择做什么运算(加、减、乘、除、混合)、做几位数的运算,再单击“开始做题”,之后计算机按要求随机生成10道题目,用户...

    JAVA小型四则运算计算器

    是用JAVA编写的小型计算器,有基本的加,减,乘,除,功能。程序结构比较简单,适合用于初学者。

    operation 简易四则运算器 java项目 简单工厂设计模式

    在本Java项目中,"operation 简易四则运算器"是一个基于简单工厂设计模式实现的计算工具,旨在帮助用户进行基本的加减乘除运算。该项目充分体现了面向对象编程的思想,通过封装、继承和多态性来提高代码的可读性和可...

    java代码-使用java创建随机加法运算器的源代码

    java代码-使用java创建随机加法运算器的源代码 ——学习参考资料:仅用于个人学习使用!

    java复数运算器

    在Java编程语言中,复数运算器是一种程序,它允许用户执行涉及复数的数学运算。复数是数学中的一个概念,表示为a + bi的形式,其中a是实部,b是虚部,i是虚数单位,满足i² = -1。这个“java复数运算器”项目提供了...

    基于java的运算器程序

    基于java的简单运算器程序 欢迎下载

    四则运算JAVA计算器

    ### 四则运算JAVA计算器知识点解析 #### 一、项目概述 该项目是一个基于Java Swing的简单计算器应用程序,能够实现基本的四则运算功能,并且支持括号操作,以解决优先级问题。为了处理复杂的数学表达式,该计算器还...

    java二进制运算器(加、见、乘、除)

    在这个Java二进制运算器中,我们将深入探讨这些基本操作以及如何在代码中实现它们。 1. **二进制数系统**: 二进制是计算机科学中的基础,只有两个数字0和1。所有的计算都在这个系统下进行,因为计算机内部处理的是...

    四则运算解析器(字符串)

    四则运算解析器是一种计算机程序,它能够接收包含加、减、乘、除等四则运算符的字符串表达式,并将其转化为可执行的计算过程。这个解析器通常用于解决基础的数学问题,对于编程初学者来说,理解并实现这样一个解析器...

    基于C#的四则运算器

    【基于C#的四则运算器】是一种编程实践项目,主要使用C#语言来实现一个基本的计算器程序,能够执行加、减、乘、除四种基本的数学运算。这个项目对于初学者来说是一个很好的起点,它能帮助理解C#编程的基础语法、控制...

    用JAVA实现复数的四则运算

    import java.io.*; public class Book{ double sb; double xb; Book(double x,double y){ this.sb=x; this.xb=y; } Book(){ } public static void main(String args[]){ System.out.println("请...

Global site tag (gtag.js) - Google Analytics