20202301 2021-2022-1 《数据结构与面向对象程序设计》实验八报告


课程:《程序设计与数据结构》
班级: 2023
姓名: 贾奕琦
学号:20202301
实验教师:王志强
实验日期:2021年11月25日
必修/选修: 必修

## 1.实验内容

  1. 参考教材PP16.1,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder)
    用JUnit或自己编写驱动类对自己实现的LinkedBinaryTree进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息
    课下把代码推送到代码托管平台

  2. 基于LinkedBinaryTree,实现基于(中序,先序)序列构造唯一一棵二㕚树的功能,比如给出中序HDIBEMJNAFCKGL和后序ABDHIEJMNCFGKL,构造出附图中的树
    用JUnit或自己编写驱动类对自己实现的功能进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息
    课下把代码推送到代码托管平台

  3. 自己设计并实现一颗决策树
    提交测试代码运行截图,要全屏,包含自己的学号信息
    课下把代码推送到代码托管平台

  4. 输入中缀表达式,使用树将中缀表达式转换为后缀表达式,并输出后缀表达式和计算结果(如果没有用树,正常评分。如果用到了树,即使有小的问题,也酌情给满分)
    提交测试代码运行截图,要全屏,包含自己的学号信息

## 2. 实验过程及结果
<1>参考教材PP16.1,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder)用JUnit或自己编写驱动类对自己实现的LinkedBinaryTree进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息,课下把代码推送到代码托管平台
代码:
节点类:
package tree;

/**
* 链式二叉树结点
* @author Administrator
*/
public class Node<S> {

/**
* 结点值
*/
private char data;
/**
* 左子树
*/
private Node<S> left;
/**
* 右子树
*/
private Node<S> right;

public Node(char i,Node left,Node right) {
this.data=data;
this.left=left;
this.right=right;

}
@Override
public String toString() {
return ""+data;
}

public char getData() {
return data;
}
public void setData(char data) {
this.data = data;
}

public Node<S> getLeft() {
return left;
}

public void setLeft(Node<S> left) {
this.left = left;
}

public Node<S> getRight() {
return right;
}

public void setRight(Node<S> right) {
this.right = right;
}
}
LinkedBinaryTree
package tree;

public class LinkedBinaryTree<T> implements BinaryTree {

public LinkedBinaryTree(Node node1) {
this.root=node1;
}

public static class Node{
Object data;
Node left;
Node right;
public Node(Object data){
this.data=data;
this.left=null;
this.right=null;
}
public Node(Object data,Node left,Node right){
this.data=data;
this.left=left;
this.right=right;
}
}

private Node root;



@Override
public int size() {
System.out.print("二叉树结点的个数是:");
return this.size(root);
}

private int size(Node root) {
if (root == null){
return 0;
}else{
int nl = this.size(root.left);
int nr = this.size(root.right);
return nl+nr+1;
}
}
@Override
public int getHeight() {
System.out.print("二叉树的高度是:");
return this.getHeight(root);
}

private int getHeight(Node root) {
if (root == null) {
return 0;
} else{
int nl = this.getHeight(root.left);
int nr = this.getHeight(root.right);
return nl>nr?nl+1:nr+1;
}
}
@Override
public Node contains(Object data) {
return this.findKey(data , root);
}

private Node findKey(Object data, Node root) {
if (root == null){//递归结束条件1:结点为空,可能是整个树的根结点,也可能是递归调用中叶子结点中左孩子和有孩子
return null;

}else if (root !=null && root.data == data){//递归结束条件2:找到了
return root;
}else {
//递归体
Node node1 = this.findKey(data, root.left);
Node node2 = this.findKey(data, root.right);
if (node1 != null && node1.data == data){
return node1;
}else if (node2 != null && node2.data == data){
return node2;
}else {
return null;
}
}

}
@Override
public void preOrderTraverse() {
System.out.print("先序遍历:");
preOrderTraverse(root);
System.out.println();
}

private void preOrderTraverse(Node root) {
if (root != null){
//1.输出跟
System.out.print(root.data+" ");
//2.遍历左
preOrderTraverse(root.left);
//3.遍历右
preOrderTraverse(root.right);
}
}
@Override
public void inOrderTraverse() {
System.out.print("中序遍历:");
inOrderTraverse(root);
System.out.println();
}

private void inOrderTraverse(Node root) {
if (root != null){
//1.遍历左子树
this.inOrderTraverse(root.left);
//2.输出根的值
System.out.print(root.data+" ");
//3.遍历右子树
this.inOrderTraverse(root.right);
}
}
@Override
public void postOrderTraverse() {
System.out.print("后序遍历:");
postOrderTraverse(root);
System.out.println();
}


private void postOrderTraverse(Node node) {
if (node != null){
//1.遍历左子树
this.postOrderTraverse(node.left);
//2.遍历右子树
this.postOrderTraverse(node.right);
//3.输出根的值
System.out.print(node.data+" ");
}

}
@Override
public String toString() {
return "" + root.data;
}
@Override
public LinkedBinaryTree<T> getRight(Object data) {
if (root == null) {
System.out.println("空树");
return null;
}
else if(contains(data)==null){
System.out.println("节点不存在");
return null;
}
else{
LinkedBinaryTree<T> result = new LinkedBinaryTree<T>(root);
result.root = root.right;
return result;
}
}
测试:
package tree;

import org.junit.*;

import java.util.TreeMap;

public class LinkedBinaryTreeTest {
private LinkedBinaryTree.Node node1,node2,node3,node4,node5,node6,node7;
public BinaryTree binaryTree;
@Before
public void setUp() throws Exception {
//创建树的结点
TreeMap map;
node5 = new LinkedBinaryTree.Node(4,null,null);
node7 = new LinkedBinaryTree.Node(3,null,null);
node3 = new LinkedBinaryTree.Node(2,null,null);
node6 = new LinkedBinaryTree.Node(1,null,node7);
node4 = new LinkedBinaryTree.Node(23,null,node5);
node2 = new LinkedBinaryTree.Node(20,node3,node6);
node1 = new LinkedBinaryTree.Node(20,node4,node2);
//创建二叉树
binaryTree = new LinkedBinaryTree(node1);

}

@Test
public void size() {
//二叉树结点的个数是
System.out.println(binaryTree.size());
}

@Test
public void getHeight() {
//二叉树的高度是
System.out.println(binaryTree.getHeight());
}

@Test
public void findKey() {
System.out.println(binaryTree.contains(23));
}

@Test
public void preOrderTraverse() {
//先序遍历:20 23 4 20 2 1 3
binaryTree.preOrderTraverse();
}

@Test
public void inOrderTraverse() {
//中序遍历:23 4 20 2 20 1 3
binaryTree.inOrderTraverse();
}


@Test
public void postOrderTraverse() {
//后序遍历:4 23 2 3 1 20 20
binaryTree.postOrderTraverse();
}

@Test
public void getRight() {
System.out.println("查询的节点的右孩子是:"+binaryTree.getRight(20));
System.out.println("查询的节点的右孩子是:"+binaryTree.getRight(7));
}
}
测试截图:

树:

 

 

<2> 基于LinkedBinaryTree,实现基于(中序,先序)序列构造唯一一棵二㕚树的功能,比如给出中序HDIBEMJNAFCKGL和后序ABDHIEJMNCFGKL,构造出附图中的树用JUnit或自己编写驱动类对自己实现的功能进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息,课下把代码推送到代码托管平台

补充方法:

public void  cal_tree(String smid, String slast) {
boolean state = StringEquals(smid, slast);
if (state == false )
return ;
if (smid.length() == 0 )
return ;

if (smid.length() == 1 ) {
res += smid;
return ;
}
char root = slast.charAt(slast.length()- 1 );
int mid = smid.indexOf(root);
String c=smid.substring( 0 , mid);
String d = smid.substring(mid+ 1 );
res += String.valueOf(root);
cal_tree(c,slast.substring( 0 , c.length()));
cal_tree(d,slast.substring(c.length(),slast.length()- 1 ));
return ;
}
public static String res = "";
public static boolean StringEquals(String a1, String a2) {
boolean state = true ;
if (a1.length() != a2.length()) {
state = false ;
}
if (a1.length() == a2.length()) {
for ( int i = 0 ; i < a1.length(); i++) {
if (a2.indexOf(a1.charAt(i)) == - 1 )
state = false ;
}
}
return state;
}
}

测试:

package tree;

import static tree.LinkedBinaryTree.res;

public class test {
public static void main(String[] agrs) {
LinkedBinaryTree linkedBinaryTree=new LinkedBinaryTree(null);
String s1 = "YIJAQ" ;
String s2 = "YIQAJ" ;
linkedBinaryTree.cal_tree(s1, s2);
if (res.length() != s1.length())
{
System.out.println( "wrong tree list!" );
}
else {
System.out.println("前序遍历为:"+res);
}
}
}
截图:

树:

 

 

 

 

<3>自己设计并实现一颗决策树,提交测试代码运行截图,要全屏,包含自己的学号信息,课下把代码推送到代码托管平台

代码:

package tree;

import java.util.Scanner;

public class DecisionTree {
private static Scanner scanner=new Scanner(System.in);
private static Node1<String> root= new Node1<>("你会不会Java?0/1");

public static void main(String[] args)
{
buildDTree();
runDTree(root);
}
public static void buildDTree(){
root= new Node1<>("你会不会Java?0/1");
Node1<String> temp=root;
temp.left= new Node1<>("不会,放弃吗?0/1");
temp.right= new Node1<>("会");

temp=temp.left;
temp.left= new Node1<>("绝不放弃!!!");
temp.right= new Node1<>("放弃?0/1");

temp=temp.right;
temp.left= new Node1<>("嘿嘿!不可能的!!!");
temp.right= new Node1<>("中国人不说放弃!!!!");
}

public static void runDTree(Node1 root){
System.out.println(root.data);
if (root.left==null||root.right==null){
return;
}
while (true){
Scanner scanner=new Scanner(System.in);
int slect=scanner.nextInt();

if (slect==1){
runDTree(root.right);
break;
}
else if (slect==0){
runDTree(root.left);
break;
}
else {
System.out.println("输入错误!重新输入。");
}
}
}
public static class Node1<S> {
private S data;
private Node1<S> left;
private Node1<S> right;

public Node1(S data) {
this.data=data;
}
}
}
运行截图:

 

 二叉树:

 

 

<4>输入中缀表达式,使用树将中缀表达式转换为后缀表达式,并输出后缀表达式和计算结果(如果没有用树,正常评分。如果用到了树,即使有小的问题,也酌情给满分),提交测试代码运行截图,要全屏,包含自己的学号信息

补充代码:

public static class Fix {
static Stack<Character> op = new Stack<>();

public static Float calculate(char op, Float f1, Float f2) {
if (op == '+') return f2 + f1;
else if (op == '-') return f2 - f1;
else if (op == '*') return f2 * f1;
else if (op == '/') return f2 / f1;
else return Float.valueOf(-0);
}

public static float calrp(String rp) {
Stack<Float> v = new Stack<>();
char[] arr = rp.toCharArray();
int len = arr.length;
for (int i = 0; i < len; i++) {
Character ch = arr[i];
if (ch >= '0' && ch <= '9') v.push(Float.valueOf(ch - '0'));
else v.push(calculate(ch, v.pop(), v.pop()));
}
return v.pop();
}

public static String getrp(String s) {
char[] arr = s.toCharArray();
int len = arr.length;
String out = "";
for (int i = 0; i < len; i++) {
char ch = arr[i];
if (ch == ' ') continue;
if (ch >= '0' && ch <= '9') {
out += ch;
continue;
}
if (ch == '(')
op.push(ch);
if (ch == '+' || ch == '-') {
while (!op.empty() && (op.peek() != '('))
out += op.pop();
op.push(ch);
continue;
}
if (ch == '*' || ch == '/') {
while (!op.empty() && (op.peek() == '*' || op.peek() == '/'))
out += op.pop();
op.push(ch);
continue;
}
if (ch == ')') {
while (!op.empty() && op.peek() != '(')
out += op.pop();
op.pop();
continue;
}
}
while (!op.empty()) out += op.pop();
return out;
}
}
测试:
import java.util.Stack;
import java.util.Scanner;
public class TreeShift {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入表达式:");
String s = scan.nextLine();
Fix fix = new Fix();
System.out.println("后缀表达式为:\n" + Fix.getrp(s));
System.out.println("计算结果为:\n" + fix.calrp(Fix.getrp(s)));
}
运行截图:

 

 

3. 实验过程中遇到的问题和解决过程

问题1:

一开始看题,没看懂,那个参考是在哪(手动笑哭)

问题1解决:

仔细翻了翻

其他(感悟、思考等)

这一次实验涉及到了树的构建、通过前序与中序构造树还有决策树的构建。虽然在最后一个中缀转后缀中我没能用树的结构来实现,但是通过栈和队列两种线性结构来实现这个功能难度依然不小,花费时间较多。这些编程实践能够让我们对一些经典的数据结构有更深刻的理解。

参考资料

posted @ 2021-11-28 16:30  20202301贾奕琦  阅读(27)  评论(0编辑  收藏  举报