本打算做一个从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;

} }}

java四则运算器算法_java写的四则运算器相关推荐

  1. java密码学原型算法_java密码学原型算法实现——双线性对.pdf

    java密码学原型算法实现--双线性对 Java 密码学原型算法实现--双线性对 1.背景介绍 如何使用jPBC 库进行双线性群初始化,包括: (1)质数阶双线性群(Prime-Order Bilin ...

  2. java 求交集 算法_Java计算交集,差集,并集的方法示例

    Java计算交集,差集,并集的方法示例 发布时间:2020-10-07 10:37:46 来源:脚本之家 阅读:106 作者:benbenkui 本文实例讲述了Java计算交集,差集,并集的方法.分享 ...

  3. java 数独算法_JAVA写的数独,附带生成唯一解和各种难度的算法

    [实例简介] 自己用GUI写的一个数独小游戏..可选择难度,生成一个只有唯一解的数独..可显示答案,玩家也可以自己做题.代码+算法全在里面 [实例截图] [核心代码] Sudoku ├── Sudok ...

  4. java实现简单四则运算_JAVA实现简单四则混合运算

    java实现加减乘除混合运算, http://www.oschina.net/code/snippet_189899_36597 这个算法很好, 加法 加号前面的加上加号后面的 减法 减号前面的减去减 ...

  5. java gc回收算法_Java GC回收算法-判定一个对象是否可以回收

    开源推荐 推荐一款一站式性能监控工具(开源项目) Pepper-Metrics是跟一位同事一起开发的开源组件,主要功能是通过比较轻量的方式与常用开源组件(jedis/mybatis/motan/dub ...

  6. java 年轻代算法_java内存模型 年轻代/年老代 持久区,jvm中的年轻代 老年代 持久代 gc...

    虚拟机中的共划分为三个代:年轻代(Young Generation).老年代(Old Generation)和持久代(Permanent Generation).其中持久代主要存放的是Java类的类信 ...

  7. java实现随机数生成算法_Java 语言实现的随机数生成算法

    广州疯狂软件学院拥有三大课程体系包括:java课程,android课程,ios课程,疯狂软件年终钜惠,报名java就业班,免费赠送基础班,名额有限,本月火热报名中,欢迎有志之士电话或者QQ咨询. [导 ...

  8. java快速查找算法_Java实现的快速查找算法示例

    本文实例讲述了Java实现的快速查找算法.分享给大家供大家参考,具体如下: 快速查找算法,可以根据想要找的是第几个大的数,每次循环都能固定下来一个数在数组完整排完序之后的位置,每次循环都能定一个数的位 ...

  9. java编写一个通讯录_java写的通讯录(小玩意)

    上次有发个超级菜鸟级别的连接access的小程序 受兄弟委托,如今表妹期末了,要写个通讯录 于是草草的给写了个,毕竟有一个学期了,所以这次的代码会比较合理些-- 使用说明: 实现技术:java语言,界 ...

最新文章

  1. 开发顺序工作流时注意的几个事项
  2. FJWC 2019 游记
  3. php万年历上个月下个月,php 万年历
  4. mysql 查询语句_SQL语言mysql基础查询语句
  5. Java GregorianCalendar computeFields()方法与示例
  6. NginxJava笔记-Webservice使用HTTPS协议及Spring Boot配置tomcat
  7. html页面底部白条,用cookie解决新版微信中H5页面底部白条问题
  8. java thread join()_Java中Thread.join()的使用方法
  9. HTTP与Tcp协议下双工通信的差异
  10. 计算机信息管理试卷答案,计算机信息管理专业《计算机组成原理》试卷B和参考答案4...
  11. jQuery中的css部分
  12. 安装Linux系统的一些问题记载
  13. python函数速查手册_Pandas常用函数速查手册中文版
  14. python http请求时gzip解压
  15. 亲民地理第39期-佛山(2)南风古灶
  16. 看完必会的正则表达式和递归
  17. mysql自定义函数的创建
  18. 花生棒虚拟服务器,花生棒 开服务器
  19. PQI Air Card:自带Wi-fi的闪存卡 即时分享精彩画面
  20. minigui源码学习

热门文章

  1. dbms_job涉及到的知识点
  2. 2009年下半年信息系统项目管理师上午试题分析与解答文档
  3. windows常见软件库
  4. arm-none-eabi-gcc install
  5. Example3_3(if-else语句)
  6. 使用ILmerge合并Exe、Dll文件的帮助类
  7. Javadoc的使用
  8. 推荐四十多条纯干货 Java 代码优化建议
  9. hotmail在outlook2007中的设置
  10. ①Windows Server 8基于远程桌面服务方案的安装