20202307 实验八《树》实验报告
20202307 2021-2022-1 《数据结构与面向对象程序设计》实验八报告
课程:《程序设计与数据结构》
班级: 2023
姓名: 范宇涵
学号:20202307
实验教师:王志强
实验日期:2021年11月25日
必修/选修: 必修
1.实验内容
-
参考教材PP16.1,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder)
用JUnit或自己编写驱动类对自己实现的LinkedBinaryTree进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息
课下把代码推送到代码托管平台 -
基于LinkedBinaryTree,实现基于(中序,先序)序列构造唯一一棵二?树的功能,比如给出中序HDIBEMJNAFCKGL和后序ABDHIEJMNCFGKL,构造出附图中的树
用JUnit或自己编写驱动类对自己实现的功能进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息
课下把代码推送到代码托管平台 -
自己设计并实现一颗决策树
提交测试代码运行截图,要全屏,包含自己的学号信息
课下把代码推送到代码托管平台 -
输入中缀表达式,使用树将中缀表达式转换为后缀表达式,并输出后缀表达式和计算结果(如果没有用树,正常评分。如果用到了树,即使有小的问题,也酌情给满分)
提交测试代码运行截图,要全屏,包含自己的学号信息
2.实验过程及结果
LinkedBinaryTree
- 链树的实现:
https://gitee.com/besti2023javads/fan-yuhan-20202307/blob/master/src/Exp8/LinkedBinaryTree.java
https://gitee.com/besti2023javads/fan-yuhan-20202307/blob/master/src/Exp8/Test.java
-
基于中序、先序序列构造树:
构造思路:明确不同遍历的特征,确定边界
二叉树前序遍历:先根节点,后左子树,再右子树
二叉树中序遍历:先左子树,后根节点,再右子树先序表达式的第一位是根节点,在中序表达式中找到根节点,表达式左边即为左子树,右边即为右子树。把表达式左边当成一个新的中序表达式,重复上述操作,可根据递归思想构造完成。
https://gitee.com/besti2023javads/fan-yuhan-20202307/blob/master/src/Exp8/Test2.java
- 设计决策树:基于链树实现,将决策信息填入结点中,定义一个访问方法,设置判定条件为输入n即访问左子树,输入y即访问右子树。
https://gitee.com/besti2023javads/fan-yuhan-20202307/blob/master/src/Exp8/DecisionTree.java
https://gitee.com/besti2023javads/fan-yuhan-20202307/blob/master/src/Exp8/Test3.java
- 中缀转后缀并计算:当遇到数字时,直接存入后缀表达式;当遇到符号时,若栈顶元素优先级高于等于这个符号,栈顶元素出栈存入表达式,符号入栈,若栈顶元素优先级低于它直接入栈。当遇到“(”时直接存入,遇到“)”匹配上一个“(”,“()”中间所有元素全部出栈。
https://gitee.com/besti2023javads/fan-yuhan-20202307/blob/master/src/Exp8/Test4.java
3.实验过程中遇到的问题及解决过程
- 问题1:总结一下现在学会的造树方法&tips:
- 问题1解决方案:
- 递归造树时,使用数组自增a[i++]。
- 非递归造树时,根据需求定义多个add方法,填充空树。
- 树的实现具体靠链式结构还是数组结构视情况而定。有些时候通过数组下标访问会更快。比如数组下标为n的左右子树下标分别为2n及2n+1.
- 有些树需要借助其他数据类型构造。比如根据前序、中序、后序表达式构造一棵树,需要用到栈。
- 大多数情况下还是用递归造树,造了这么多树,虚空结点的树我觉得比较典型,造树代码如下:
public Tree(String str) {
StringTokenizer stringTokenizer = new StringTokenizer(str);
String[] a=new String[20];
int j=0;
while (stringTokenizer.hasMoreTokens()) {
a[j++]= stringTokenizer.nextToken();
}
//一定要把root换成create后的root
root=CreateTree(root,a);
}
//建立虚空结点的树
public Node CreateTree(Node x,String[] data) {
String temp=data[i++];
if (temp.equals("#"))
return null;
else{
x=new Node(temp);
x.setLeft(CreateTree(x.getLeft(),data));
x.setRight(CreateTree(x.getRight(),data));
}
return x;
}
- 问题2:前序遍历的递归和非递归算法总结
- 问题2解决方案:
1.递归算法
void PreOrder(const TreeNode *root)
{
if (root == NULL) //若结点为空
{
printf("# ");
return;
}
printf("%c ", root->data); //输出根节点的值
PreOrder(root->left); //前序访问左子树
PreOrder(root->right); //前序访问右子树
}
2.非递归方法
void PreOrderLoop(TreeNode *root)
{
std::stack s;
TreeNode *cur, *top;
cur = root;
while (cur != NULL || !s.empty())
{
while (cur != NULL)
{
printf("%c ", cur->data);
s.push(cur);
cur = cur->left;
}
top = s.top();
s.pop();
cur = top->right;
}
}
其他(感悟、思考等)
树的结构在算法中使用非常普遍,也非常实用。它既可以用于日常生活中的分类讨论,也可以用于机器学习,通过决策树构建预测模型,推测可能的结果,帮助人们更好的决策。关于树的奥秘和用法,我将在今后的学习中不断探索。我一定会继续努力学习的!
参考资料
- https://viewer.mosoteach.cn/viewer?token=84b17eb7d75f8f1899513aa4ca9b0528&screenx=false&app_id=MTWEB&app_version=5.3.3&location=