20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告

20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告

课程:《程序设计与数据结构》

班级: 1823

姓名: 郑力元

学号:20182320

实验教师:王志强

实验日期:2019年11月11日

必修/选修: 必修

1.实验内容

1.1

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

1.2

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

1.3

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

1.4

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

2. 实验过程及结果

2.1

第一步:补充实现书上的LinkedBinaryTree类,它需要编写一个BinaryTree接口,一个节点类,两个异常类,才能完整实现LinkedBinaryTree。

20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告_第1张图片

代码如下,这里将书上的ArrayIterator换成了ArrayList:

public class LinkedBinaryTree implements BinaryTree
{
    protected BTNode root;

    public LinkedBinaryTree()
    {
        root = null;
    }

    public LinkedBinaryTree (T element)
    {
        root = new BTNode(element);
    }

    public LinkedBinaryTree (T element, LinkedBinaryTree left,
                             LinkedBinaryTree right)
    {
        root = new BTNode(element);
        root.setLeft(left.root);
        root.setRight(right.root);
    }

    public T getRootElement() throws Exception, EmptyCollectionException {
        if (root == null)
            throw new EmptyCollectionException ("Get root operation "
                    + "failed. The tree is empty.");

        return root.getElement();
    }

    public LinkedBinaryTree getLeft() throws Exception, EmptyCollectionException {
        if (root == null)
            throw new EmptyCollectionException ("Get left operation "
                    + "failed. The tree is empty.");

        LinkedBinaryTree result = new LinkedBinaryTree();
        result.root = root.getLeft();

        return result;
    }

    public T find (T target) throws ElementNotFoundException {
        BTNode node = null;

        if (root != null)
            node = root.find(target);

        if (node == null)
            throw new ElementNotFoundException("Find operation failed. "
                    + "No such element in tree.");

        return node.getElement();
    }

//返回大小
    public int size()
    {
        int result = 0;

        if (root != null)
            result = root.count();

        return result;
    }

     public LinkedBinaryTree getRight() throws Exception, EmptyCollectionException {
         if (root == null)
             throw new EmptyCollectionException ("Get left operation "
                     + "failed. The tree is empty.");

         LinkedBinaryTree result = new LinkedBinaryTree();
         result.root = root.getRight();

         return result;
     }

     public boolean contains (T target) {
        if (root.find(target)==null){
            return false;
        }
        else {
            return true;
        }
     }

     public boolean isEmpty() {
        if (root==null){
            return true;
        }
        else {
            return false;
        }
     }

//先序遍历
    public ArrayList preorder() {
        ArrayList iter = new ArrayList();

        if (root != null)
            root.preorder (iter);

        return iter;
    }

//后续遍历
    public ArrayList postorder() {
        ArrayList iter = new ArrayList();

        if (root != null)
            root.postorder (iter);

        return iter;
    }
     public String toString() {
         return super.toString();
     }
}

第二步:编写测试代码,运行

20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告_第2张图片

2.2

第一步:修改上面的LinkedBinaryTree方法,将先序、中序和后序遍历都改成返回字符串,同时加入能够从上到下构造二叉树的方法:

    public int findIndexInArray(char[] a, char x, int begin, int end) {
        for(int i=begin;i<=end;i++) {
            if(a[i] == x) {
                return i;
            }
        }
        return -1;
    }


    public void initTree(char[] preOrder, char[] inOrder) {
        this.root = this.initTree(preOrder, 0, preOrder.length-1, inOrder, 0, inOrder.length-1);
    }

    public BTNode initTree(char[] preOrder, int start1, int end1, char[] inOrder, int start2, int end2) {
        if(start1 > end1 || start2 > end2) {
            return null;
        }
        //通过前序找到根结底
        char rootData = preOrder[start1];
        BTNode head = new BTNode(rootData);
        //从中序遍历里找到根结点所在的位置
        int rootIndex = findIndexInArray(inOrder, rootData, start2, end2);
        //offSet代表左子树的长度-1(也就是中序遍历中,左子树最后一个元素的下标)
        int offSet = rootIndex - start2 - 1;
        //递归构建左子树
        BTNode left = initTree(preOrder, start1+1, start1+1+offSet, inOrder, start2, start2+offSet);
        //递归构建右子树
        BTNode right = initTree(preOrder, start1+offSet+2, end1, inOrder, rootIndex+1, end2);
        head.left = left;
        head.right = right;
        return head;
    }

第二步:编写测试代码,运行,这里用后续遍历检验是否正常构建二叉树

20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告_第3张图片

2.3

第一步:编写好节点类和决策树类(包含主方法和构建与运行决策树的方法)

    public static void buildDTree(){
        root=new BTNode("大力帅吗?y/n");
        BTNode temp=root;
        temp.left=new BTNode<>("你错了。");
        temp.right=new BTNode<>("大力聪明吗?y/n");

        temp=temp.right;
        temp.left=new BTNode<>("你错了。");
        temp.right=new BTNode<>("大力强吗?y/n");

        temp=temp.right;
        temp.left=new BTNode<>("你错了。");
        temp.right=new BTNode<>("你说的都对了。");
    }

    public static void runDTree(BTNode root){
        System.out.println(root.element);
        if (root.left==null||root.right==null){
            return;
        }
        while (true){
            stringTokenizer=new StringTokenizer(scanner.nextLine());
            String string=stringTokenizer.nextToken();

            if (string.equals("y")){
                runDTree(root.right);
                break;
            }
            else if (string.equals("n")){
                runDTree(root.left);
                break;
            }
            else {
                System.out.println("输入错误!重新输入。");
            }
        }
    }

第二步:运行

20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告_第4张图片
20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告_第5张图片

2.4

第一步:编写中缀转后缀的类(包括主方法):

public static String infixToSuffix(String infix) {
        Stack stack = new Stack();
        String suffix = "";
        int length = infix.length();
        for (int i = 0; i < length; i++) {
            Character temp;
            char c = infix.charAt(i);
            switch (c) {
                // 忽略空格
                case ' ':
                    break;
                // 碰到'(',push到栈
                case '(':
                    stack.push(c);
                    break;
                // 碰到'+''-',将栈中所有运算符弹出,送到输出队列中
                case '+':
                case '-':
                    while (stack.size() != 0) {
                        temp = stack.pop();
                        if (temp == '(') {
                            stack.push('(');
                            break;
                        }
                        suffix += " " + temp;
                    }
                    stack.push(c);
                    suffix += " ";
                    break;
                // 碰到'*''/',将栈中所有乘除运算符弹出,送到输出队列中
                case '*':
                case '/':
                    while (stack.size() != 0) {
                        temp = stack.pop();
                        if (temp == '(' || temp == '+' || temp == '-') {
                            stack.push(temp);
                            break;
                        } else {
                            suffix += " " + temp;
                        }
                    }
                    stack.push(c);
                    suffix += " ";
                    break;
                // 碰到右括号,将靠近栈顶的第一个左括号上面的运算符全部依次弹出,送至输出队列后,再丢弃左括号
                case ')':
                    while (stack.size() != 0) {
                        temp = stack.pop();
                        if (temp == '(')
                            break;
                        else
                            suffix += " " + temp;
                    }
                    // suffix += " ";
                    break;
                //如果是数字,直接送至输出序列
                default:
                    suffix += c;
            }
        }

        //如果栈不为空,把剩余的运算符依次弹出,送至输出序列。
        while (stack.size() != 0) {
            suffix += " " + stack.pop();
        }
        return suffix;
    }

第二步:运行

20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告_第6张图片

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

问题1:

原本是想基于LinkedBinaryTree的构造二叉树的方法,完成8.2的二叉树的构建,但是发现LinkedBinaryTree的原本构造方法是自下而上构造二叉树的,然而已知的先序和中序遍历能确定的根是在二叉树的最顶端

问题1解决:

自己加了一个自上而下的构造二叉树的方法,实现功能。

其他(感悟、思考等)

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

参考资料

  • 《Java程序设计与数据结构教程(第二版)》

  • 《Java程序设计与数据结构教程(第二版)》学习指导

  • 《Java和安卓开发学习指南(第二版)》

你可能感兴趣的:(20182320 2019-2020-1 《数据结构与面向对象程序设计》实验8报告)