实验二:表达式二叉树构建以及遍历
《数据结构》实验二报告
学号: XXXXXXXXX |
机器号 10-413 |
姓名: xxx |
日期: 2020-11-18 |
程序名: Test.java |
|
实验内容: 二叉树的遍历 |
一、目的和要求(需求分析):
1、掌握二叉树的存储结构以及二叉树的建立和操作。
2、输入一串表达式后,建立二叉树,并对其进行先序、中序和后序的遍历。
(输入表达式如此形式:a+b*c-d-e/f….;以#号结束。)
3、递归实现表达式运算。
二、程序设计的基本思想,原理和算法描述:
1.程序结构:
主程序:Main函数
结构体-二叉树节点:class BTree_Node
结构体-二叉树树结构:class BTree
递归构造二叉树表达式:class BTree_Node init
释放二叉树节点:void destory_Tree
先序遍历:void preshow
中序遍历:void midshow
后序遍历:void posshow
Java直接计算表达式:void Output_1
递归输出表达式的值:double Output_2
2.数据结构:
本程序使用java语言来实现二叉树表达式的构造以及输出,首先创建输入表达式字符串,经过init函数递归构造表达式二叉树,将中缀表达式先替换为后缀表达式,并对+-*/符号进行手动的优先级判断。最后使用前序,中序,后序遍历输出。最后使用输出方法1:java中与js互相应用的ScriptEngineManager直接计算表达式的值,输出方法2:递归方式计算表达式树。
public static BTree_Node init(String str,int star,int end) {//递归构造树 int num_oper=0; BTree_Node bnNode=new BTree_Node(null); BTree_Node p=new BTree_Node(null); int k; int pos=0; //核心代码,递归时优先递归*/号,之后再+-号 //pos代表递归当前位置 if(star==end) {//递归结束条件 char ch=str.charAt(star); bnNode.data=ch+""; //System.out.println(bnNode.data); bnNode.lTree=bnNode.rTree=null; return bnNode; } else { //下面就是递归判断条件 //i!=j:查找运算符 for(k=star;k<=end;k++) { char ch1=str.charAt(k); if(ch1=='+'||ch1=='-') { num_oper++; pos=k;//记录位置 } } if(num_oper==0) {//没有+- for(k=star;k<=end;k++) { char ch2=str.charAt(k); if(ch2=='*'||ch2=='/') { num_oper++; pos=k; } } } if(num_oper!=0) {//递归构造左右子树 p.data=str.charAt(pos)+""; p.lTree=init(str, star, pos-1); p.rTree=init(str, pos+1, end); }else { return null; } } //System.out.println(p.data); return p; } 3.输入输出设计: 输入: Scanner input_1=new Scanner(System.in);//输入字符串 String string=input_1.next(); char ending=string.charAt(string.length()-1); while(ending!='#') { string+=input_1.next(); ending=string.charAt(string.length()-1); } string=string.substring(0, string.length()-1);//到这里才结束输入字符串 输出: private static void preshow(BTree_Node root) {//先序遍历 // TODO Auto-generated method stub if(root!=null) { System.out.print(root.getData()+" "); preshow(root.getlTree()); preshow(root.getrTree()); } } private static void midshow(BTree_Node root) {//中序遍历 // TODO Auto-generated method stub if(root!=null) { midshow(root.getlTree()); System.out.print(root.getData()+" "); midshow(root.getrTree()); } } private static void posshow(BTree_Node root) {//后序遍历 // TODO Auto-generated method stub if(root!=null) { posshow(root.getlTree()); posshow(root.getrTree()); System.out.print(root.getData()+" "); } }
三、调试和运行程序过程中产生的问题及采取的措施:
1.递归构造二叉树寻找结束递归条件以及递归条件的判断有很大的十五
解决方法:多次进行条件尝试,对于每一个部分都使用临时输出和断点的方法来测试,并且结合百度以及课本的知识解决。而且对于二叉表达式,首先就是按照从左到右依次寻找最右面的+-*/号,然后递归从该位置开始的左右递归,从而达到构造的作用
3.递归方法计算表达式树的时候计算错误,递归算法没有计算好
解决方法:1.使用java特有的包直接计算字符串的值
2.先画图画出来整个二叉树的结构,然后再写上去
2.中序表达式很难直接构造表达式二叉树
解决方法:先转换为后缀表达式,然后通过后缀构造就好了
四、源程序及注释:
Test.java:
package com.atmyhome; import java.util.ArrayList; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.util.Scanner; public class Test { static public class BTree_Node{//节点 private String data;//值 private BTree_Node lTree;//左子树 private BTree_Node rTree;//右子树 public BTree_Node(String data) { this.data=data; } public String getData() { return data; } public BTree_Node getlTree() { return lTree; } public BTree_Node getrTree() { return rTree; } } static public class BTree{//二叉树 private BTree_Node rootNode=new BTree_Node(null); ArrayList<BTree_Node> number=new ArrayList<>(); ArrayList<BTree_Node> operations=new ArrayList<>();//本来是想储存运算符和数字的,最后好像不需要。。 public BTree_Node getrootNode() { return rootNode; } } public static BTree_Node init(String str,int star,int end) {//递归构造树 int num_oper=0; BTree_Node bnNode=new BTree_Node(null); BTree_Node p=new BTree_Node(null); int k; int pos=0; //核心代码,递归时优先寻找递归+-号,之后再*/号 //pos代表递归当前位置 if(star==end) {//递归结束条件 char ch=str.charAt(star); bnNode.data=ch+""; //System.out.println(bnNode.data); bnNode.lTree=bnNode.rTree=null; return bnNode; } else { //下面就是递归判断条件 //i!=j:查找运算符 for(k=star;k<=end;k++) { char ch1=str.charAt(k); if(ch1=='+'||ch1=='-') { num_oper++; pos=k;//记录位置 } } if(num_oper==0) {//没有+- for(k=star;k<=end;k++) { char ch2=str.charAt(k); if(ch2=='*'||ch2=='/') { num_oper++; pos=k; } } } if(num_oper!=0) {//递归构造左右子树 p.data=str.charAt(pos)+""; p.lTree=init(str, star, pos-1); p.rTree=init(str, pos+1, end); }else { return null; } } //System.out.println(p.data); return p; } public static void show(BTree_Node root) {//遍历 System.out.println("先序递归遍历"); preshow(root); System.out.println(""); System.out.println("中序递归遍历"); midshow(root); System.out.println(""); System.out.println("后序递归遍历"); posshow(root); System.out.println(""); } public void destory_Tree(BTree_Node root){//释放内存 if(root!=null) { destory_Tree(root.lTree); destory_Tree(root.rTree); root=null; } } private static void preshow(BTree_Node root) {//先序遍历 // TODO Auto-generated method stub if(root!=null) { System.out.print(root.getData()+" "); preshow(root.getlTree()); preshow(root.getrTree()); } } private static void midshow(BTree_Node root) {//中序遍历 // TODO Auto-generated method stub if(root!=null) { midshow(root.getlTree()); System.out.print(root.getData()+" "); midshow(root.getrTree()); } } private static void posshow(BTree_Node root) {//后序遍历 // TODO Auto-generated method stub if(root!=null) { posshow(root.getlTree()); posshow(root.getrTree()); System.out.print(root.getData()+" "); } } private static void Output_1(String string) {//java版本的直接对字符串表达式计算 // TODO Auto-generated method stub ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn"); String expression = string; try { String result = String.valueOf(scriptEngine.eval(expression)); System.out.println("Java特有对表达式直接计算"+result); } catch (ScriptException e) { e.printStackTrace(); } } //递归方式计算表达式树 public static double Output_2 (BTree_Node root) { if(!(root.data.equals("+") || root.data.equals("-")||root.data.equals("*")||root.data.equals("/"))) return Double.parseDouble(root.data); else if(root.data.equals("+"))//加法 { return Output_2(root.lTree) + Output_2(root.rTree); } else if(root.data.equals("-"))//减法 { return Output_2(root.lTree) - Output_2(root.rTree); } else if(root.data.equals("*"))//乘法 { return Output_2(root.lTree) * Output_2(root.rTree); } else if(root.data.equals("/"))//除法 { return Output_2(root.lTree) / Output_2(root.rTree); } else { return 0; } } public static void main(String[] args) { BTree bTree=new BTree();//创建二叉树 BTree_Node node=new BTree_Node(null); Scanner input_1=new Scanner(System.in);//输入字符串 String string=input_1.next(); char ending=string.charAt(string.length()-1); while(ending!='#') { string+=input_1.next(); ending=string.charAt(string.length()-1); } string=string.substring(0, string.length()-1);//到这里才结束输入字符串 node=init(string,0,string.length()-1);//这里为了方便就直接写表达式了 show(node); System.out.println("输出结果:"); Output_1(string);//输出方法1: System.out.println("递归方法计算"+Output_2(node));//输出方法2: } }
五、运行输出结果:
六、心得与体会:
心得:
由于本次没有上机给老师查看代码,所以我这个实验亮点就写在这里面了。本次实验我使用java做的,首先是我构造表达式二叉树的时候,是使用递归方法来构造表达式二叉树的,不是先转化为后缀表达式再进行构造,而是先去找到表达式中最后一个运算符号,然后依次向表达式前后,也就是树的上下进行递归构造,好吧,本质上都差不多。同时递归过程中也可以很清楚的看到每个节点及其父子树的位置关系。
另外再说一下遍历吧,遍历都是差不多的,我这里也是使用递归遍历,但是我在网上还寻找到了java与js互相调用的特殊函数ScriptEngine,可以直接根据输入的表达式进行计算,这个我是感觉是更加方便的。
最后说一下,我这个程序虽说基本功能都可以实现,但是没有考虑到括号的影响,下次我会多多查询课本和网上资料来填补细节上的缺陷。谢谢。
体会:
掌握二叉树的存储结构以及二叉树的建立和操作,对二叉树的输入和输出有了更加深入的体验,输入一串表达式后,建立二叉树,并对其进行先序、中序和后序的遍历。并且了解并深入学习了递归实现表达式运算的方法。并且也通过这次实验更加深入了解JAVA语言的魅力。