大学学习数据结构的时候做过一个计算算术表达式字符串结果的小程序,最近学习java接触到了类似的问题,不过不是计算结果,而是利用它来构造二叉树,难度稍微大了一些。我在这里提供两种解决方案。相信很多人都知道怎么计算表达式的值,利用两个栈(符号栈和数字栈)根据运算符优先级进行出栈入栈操作,我们知道将栈中的运算符和数字替换为二叉树的节点就可以在这个过程中顺利的构造一个二叉树出来。第二种方法利用了递归的思想,我们构造二叉树的难点其实主要在于括号的存在,假设一个没有括号的算数表达式,如1+2*3-8/4,我们取得第一个运算符+的时候,将其作为一个树节点,将1和2分别作为左孩子和右孩子;当我们取得*时,将2和3分别作为它的左右孩子,由于*优先于+,所以*将成为+的右孩子;当我们取得-时,将3和8作为其左右孩子,由于-优先级低于*,所以要往上找*的父亲+,由于-的优先级低于+,所以继续找+的父亲,由于+已经没有父亲,+将成为-的孩子;最后取得/时,由于/优先级高于-,所以直接作为-的右孩子。个人感觉这两种方法都比较好理解。第二种方法的二叉树构造顺序如下(直线上的数字代表构造的次序,比较有趣的是用第一种方法和第二种方法构造出来的二叉树好像是一样的):
其中用到了基本的数据结构树节点TreeNode<E>,使用时应该用TreeNode<Character>,特别注意第一种方法不要求树节点中保存父指针,但第二种要求要保留父指针。两种方法的核心代码列在下面了:
第一种:
/** * 将part解析为二叉树 * @param part * @return 返回二叉树的根节点,解析失败返回null */ public TreeNode<Character> createBinaryTree(String part){ //定义数字栈和操作符栈 Stack<TreeNode<Character>> numStack=new Stack<TreeNode<Character>>(); Stack<TreeNode<Character>> operStack=new Stack<TreeNode<Character>>(); operStack.push(new TreeNode<Character>('#',null,null,null)); for(int i=0;i<part.length();i++){ //是数字则直接压入数字栈 if(isNumber(part.charAt(i))){ numStack.push(new TreeNode<Character>(part.charAt(i),null, null,null)); continue; } //是操作符(注意这里没有把左右括号当做操作符)或者左括号,则尝试压入 //符号栈 if(isOperator(part.charAt(i))||part.charAt(i)=='('){ Character top=operStack.get(operStack.size()-1).getData(); //如果准备压入的符号比栈顶端的符号优先级低,则栈顶段的符号 //和数字栈中的数字应该弹出,两个数字是符号节点的左右孩子, //再将符号节点压入数字栈(此时该符号节点已经代表一个数字了, //所以要压入数字栈) while(getPriority(top, part.charAt(i))<0){ //如果符号栈只剩下#,说明算术表达式已经解析完了,返 //回数字栈中的节点 if(top=='#'){ return numStack.pop(); } TreeNode<Character> temp=operStack.pop(); TreeNode<Character> right=numStack.pop(); TreeNode<Character> left=numStack.pop(); temp.setLefChild(left); temp.setRigChild(right); numStack.push(temp); top=operStack.get(operStack.size()-1).getData(); } operStack.push(new TreeNode<Character>(part.charAt(i),null,null,null)); continue; } //如果将入栈的是右括号,则符号栈弹出符号并和数字栈弹出的数字组建树节 //点,知道碰到左括号。 if(part.charAt(i)==')'){ Character top=operStack.get(operStack.size()-1).getData(); while(top!='('){ TreeNode<Character> temp=operStack.pop(); TreeNode<Character> right=numStack.pop(); TreeNode<Character> left=numStack.pop(); temp.setLefChild(left); temp.setRigChild(right); numStack.push(temp); top=operStack.get(operStack.size()-1).getData(); } operStack.pop(); continue; } } return null; } 第二种方法:
/** * 利用算数字符串content构造二叉树binaryTree */ public TreeNode<Character> CreateBinaryTree(String part){ //先将表达式转换为由不含括号的节点组成的链表结构 List<TreeNode<Character>> list=new ArrayList<TreeNode<Character>>(); for(int i=0;i<part.length();i++){ if(isNumber(part.charAt(i)) || isOperator(part.charAt(i))){ list.add(new TreeNode<Character>(part.charAt(i),null,null, null)); }else { //如果不是操作数和操作符,那肯定是括号,如果表达式正确, //第一碰到的括号肯定是左括号 int right=findFitBracket(part, i); String subPart=new String(part.substring(i+1, right)); list.add(CreateBinaryTree(subPart)); i=right; } } //根据这个不含括号的链表结构构造二叉树 TreeNode<Character> cur=null; for(int i=0;i<list.size();i++){ if(isOperator(list.get(i).getData()) && list.get(i).getLefChild() ==null){ list.get(i).setLefChild(list.get(i-1)); list.get(i).setRigChild(list.get(i+1)); list.get(i-1).setFather(list.get(i)); list.get(i+1).setFather(list.get(i)); if(cur==null) cur=list.get(i); else { while(priority(cur.getData(),list.get(i).getData())<0 && cur.getFather()!=null) cur=cur.getFather(); if(cur.getFather()==null && priority(cur.getData(), list.get(i).getData())<0){ list.get(i).setLefChild(cur); cur.setFather(list.get(i)); } else { if(priority(cur.getData(), list.get(i).getData())>0){ cur.setRigChild(list.get(i)); list.get(i).setFather(cur); } } } cur=list.get(i); } } while(cur.getFather()!=null) cur=cur.getFather(); return cur; }
相关推荐
为了处理算术表达式,我们需要实现解析算法,从输入字符串(如 "2 + 3 * 4")构建二叉树。这通常涉及词法分析(将字符串分解为符号和数字)和语法分析(根据语法规则构建二叉树)。一种常见的方法是使用递归下降解析...
2. **二叉树的构造函数**:根据算术表达式构建二叉树。 3. **遍历方法**:实现前序、中序、后序遍历。 4. **计算方法**:遍历二叉树并执行相应的操作,如加、减、乘、除等。 5. **打印方法**:以中缀、前缀或后缀...
词法分析器负责识别数字、运算符和括号等符号,语法分析器则根据运算符优先级规则构建二叉树。 4. **中缀表达式转后缀表达式**:为了简化计算过程,我们可以先将中缀表达式(如2 + 3 * 4)转换为后缀表达式(如2 3 ...
1. **构建表达式树**:首先,我们可以将每个算术表达式表示为一棵二叉树,称为表达式树。叶子节点代表操作数,非叶子节点代表运算符。例如,表达式"1 +2 /3 +4"对应的树中,"1"、"2"、"3"和"4"是叶子节点,"+"和"/...
表达式二叉树,又称为运算符树或算术表达式树,它通过将运算符作为内部节点,数字作为叶节点来表示数学表达式。 在Java中,构建表达式二叉树通常涉及以下步骤: 1. **定义节点类**:创建一个名为`Node`的类,包含...
这个名为"ArvoreExpressao"的项目,显然是一个用Java实现的解决方案,用于解析和求解算术表达式,特别适合于UCS(可能是大学课程或项目)的数据结构教学。在这个项目中,我们主要会涉及到以下几个知识点: 1. **...
这个计算器基于二叉树来表示算术表达式,这是一种高效且直观的方法。 首先,我们要理解什么是二叉树。二叉树是一种特殊的数据结构,每个节点最多有两个子节点,通常分为左子节点和右子节点。在表示四则运算时,...
正确使用各种Java运算符,如一元运算符,算术运算符,关系运算符,逻辑运算符,条件运算符和赋值运算符等。 辨别使用if,if…else,switch选择结构执行不同的动作。 辨别使用while,for,do…...
二叉树在这里用于表示算术表达式,其中每个节点代表一个运算符或操作数。栈则用于处理运算符的优先级,通常在后缀表达式(逆波兰表示法)的转换和计算中起到关键作用。 2. **算法设计**: - **表达式字符串处理**...
介绍了Java中的基本数据类型,包括整型(如`int`)、浮点型(如`float`、`double`)、字符型(如`char`)等,并通过实例展示了这些数据类型的使用方法及常见的算术运算。 **1.1.2 流程控制语句** 探讨了条件判断...
根据规则,算术表达式a×b+c/d的逆波兰式是ab×c/d+,因此答案是B。 5. **循环队列**:循环队列利用数组模拟队列,头尾指针front和rear可以循环使用数组的所有位置。计算队列中元素个数时需考虑队列是否满,这里...
在Java中,它们通常用于解决特定类型的问题,如表达式解析、函数调用、任务调度等。 - **栈**:栈是一种只允许在一端进行插入和删除操作的数据结构,常用于实现函数调用栈、括号匹配检测等功能。 - **队列**:队列...
这篇实验报告主要涵盖了四方面的内容:堆排序、B+树、红黑树以及计算算术表达式的栈方法。这些都是计算机科学中重要的数据结构和算法,尤其在数据库、操作系统和编译原理等领域有着广泛应用。 1. **堆排序** - 堆...
在给定的“TreeAndHr.zip”压缩包文件中,包含了两个主要的知识点:二叉树求最近公共祖先(LCA,Lowest Common Ancestor)的算法以及一个基于Java Swing的人事系统报告生成示例。同时,描述中提到了使用`...
- 直接插入排序是一种简单的排序算法,通过构建有序序列来实现排序。 - 折半插入排序改进了直接插入排序的查找过程,提高了查找效率。 - 希尔排序是一种分组插入排序,通过比较不同间隔的元素来排序。