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

课程:《程序设计与数据结构》
班级: 1823
姓名: 赵沛凝
学号:20182301
实验教师:王志强
实验日期:2019年11月11日
必修/选修: 必修

1.实验内容

  • 参考教材PP16.1,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder),用JUnit或自己编写驱动类对自己实现的LinkedBinaryTree进行测试。
  • 基于LinkedBinaryTree,实现基于(中序,先序)序列构造唯一一棵二㕚树的功能,比如给出中序HDIBEMJNAFCKGL和先序ABDHIEJMNCFGKL,构造出附图中的树,用JUnit或自己编写驱动类对自己实现的功能进行测试。
  • 自己设计并实现一颗决策树并完成测试。
  • 输入中缀表达式,使用树将中缀表达式转换为后缀表达式,并输出后缀表达式和计算结果

2. 实验过程及结果

第一个:

  • 对这几个方法进行补充(getRight,contains,toString,preorder,postorder),代码如下:
  • getRight
public LinkedBinaryTree<T> getRight() throws Exception {
        if (root == null)
            throw new Exception ("Get Right operation "
                    + "failed. The tree is empty.");
        LinkedBinaryTree<T> result = new LinkedBinaryTree<T>();
        result.root = root.getRight();

        return result;
    }
  • contains
public boolean contains (T target) throws Exception {
        BTNode<T> node = null;
        boolean result = true;
        if (root != null)
            node = root.find(target);
        if(node == null)
            result = false;
        return result;
    }
  • preorder
public  Iterator<T> preorder() {
        ArrayIterator<T> list = new  ArrayIterator<>();

        if(root!=null)
            root.preorder(list);
        return list;
    }
  • toString
public String toString() {
        ArrayIterator<T> list = (ArrayIterator<T>) preorder();
        String result = "<top of Tree>\n";
        for(T i : list){
            result += i + "\t";
        }
        return result + "<bottom of Tree>";
    }
  • postorder
public  Iterator<T> postorder() {
        ArrayIterator<T> list = new  ArrayIterator<>();

        if(root!=null)
            root.postorder(list);
        return list;
    }

第二个

  • 运用先序、中序建立一个脑中的图像并不难,如下:
  • 但是在代码上就容易出现问题,在借鉴以及自我理解的基础上,搞了出来:
public static LinkedBinaryTree returnTree(char[] in, char[] pre)
    {
        LinkedBinaryTree tree;
        if(pre.length == 0 || in.length == 0 || pre.length != in.length){ // 终止递归的条件
            tree =  new LinkedBinaryTree();
        }
        else {
            int x = 0;
            while (in[x] != pre[0]) {   // 找到根结点
                x++;
            }

            char[] inLeft = new char[x];       // 根结点的左边为左子树,创建新的数组
            char[] preLeft = new char[x];
            char[] inRight = new char[in.length - x - 1];       // 根结点的右边为右子树,创建新的数组
            char[] preRight = new char[pre.length - x - 1];

            for (int y = 0; y < in.length; y++) {   // 把原数组的数存入新的数组当中
                if (y < x) {
                    inLeft[y] = in[y];
                    preLeft[y] = pre[y + 1];
                } else if (y > x) {
                    inRight[y - x - 1] = in[y];
                    preRight[y - x - 1] = pre[y];
                }
            }
            LinkedBinaryTree left = returnTree(inLeft, preLeft);   // 左子树递归调用
            LinkedBinaryTree right = returnTree(inRight, preRight); // 右子树递归调用
            tree = new LinkedBinaryTree(pre[0], left,right);
        }
        return tree;//HDIBEMJNAFCKGL;ABDHIEJMNCFGKL
    }
  • 本来我只弄了一个后续遍历的输出,但是看到大家都做出了树,于是又自我学习,详见问题1.
  • 最后还是出现了树哦!

第三个

  • 首先要设计决策树的脑图,构建思路,如图所示:

  • 从左向右,从上向下进行编号
  • 利用如下代码进行构建:
     LinkedBinaryTree<String>n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15;
        n15 = new LinkedBinaryTree<String>(e15);
        n14 = new LinkedBinaryTree<String>(e14);
        n11 = new LinkedBinaryTree<String>(e11,n14,n15);
        n12 = new LinkedBinaryTree<String>(e12);
        n13 = new LinkedBinaryTree<String>(e13);
        n7 = new LinkedBinaryTree<String>(e7,n12,n13);
        n8 = new LinkedBinaryTree<String>(e8);
        n9 = new LinkedBinaryTree<String>(e9);
        n5 = new LinkedBinaryTree<String>(e5,n8,n9);
        n10 = new LinkedBinaryTree<String>(e10);
        n6 = new LinkedBinaryTree<String>(e6,n10,n11);
        n4 = new LinkedBinaryTree<String>(e4);
        n2 = new LinkedBinaryTree<String>(e2,n4,n5);
        n3 = new LinkedBinaryTree<String>(e3,n6,n7);
        tree = new LinkedBinaryTree<String>(e1,n2,n3);
  • 使用如下方法进行判断
    public void diagose() throws Exception {
        Scanner scan = new Scanner(System.in);
        LinkedBinaryTree<String>current = tree;
        while (current.size() > 1)
        {
            System.out.println (current.getRootElement());
            if (scan.nextLine().equalsIgnoreCase("N"))
                current = current.getLeft();
            else
                current = current.getRight();
        }
        System.out.println (current.getRootElement());
    }

第四个

  • 首先我先搞了不使用树的中缀转后缀,代码如下:
public class Postfix {

    static Stack<Character> op = new Stack<>();

    public static float getv(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(getv(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;
    }

    public static void main(String[] args){
        System.out.println("输入中缀表达式:");
        Scanner scan=new Scanner(System.in);
        String exp=scan.nextLine();
        System.out.println("后缀表达式为:");
        System.out.println(getrp(exp));
        System.out.println("结果为:");
        System.out.println(calrp(getrp(exp)));
    }

}
  • 再有对于使用树进行中缀转后缀,其实它可以定义为表达树,

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

  • 问题1:如何真的画出一棵树呢?
  • 问题1解决方案:
  • 这个代码很复杂,需要仔细理解
    public String toString() {
        UnorderedListADT<BinaryTreeNode<T>> nodes = new ArrayListUnordered<BinaryTreeNode<T>>();
        UnorderedListADT<Integer> levelList = new ArrayListUnordered<Integer>();

        BinaryTreeNode<T> current = null;
        String result = "";
        int printDepth = this.getHeight();
        int possibleNodes = (int) Math.pow(2, printDepth + 1);
        int countNodes = 0;

        nodes.addToRear(root);
        Integer currentLevel = 0;
        Integer previousLevel = -1;
        levelList.addToRear(currentLevel);

        while (countNodes < possibleNodes) {
            countNodes = countNodes + 1;
            try {
                current = nodes.removeFirst();
            } catch (EmptyCollectionException e) {
                e.printStackTrace();
            }
            try {
                currentLevel = levelList.removeFirst();
            } catch (EmptyCollectionException e) {
                e.printStackTrace();
            }
            if (currentLevel > previousLevel) {
                result = result + "\n\n";
                previousLevel = currentLevel;
                for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++)
                    result = result + " ";
            } else {
                for (int i = 0; i < (Math.pow(2, (printDepth - currentLevel + 1)) - 1); i++) {
                    result = result + " ";
                }
            }
            if (current != null) {
                result = result + (current.getElement()).toString();
                nodes.addToRear(current.getLeft());
                levelList.addToRear(currentLevel + 1);
                nodes.addToRear(current.getRight());
                levelList.addToRear(currentLevel + 1);
            } else {
                nodes.addToRear(null);
                levelList.addToRear(currentLevel + 1);
                result = result + " ";
            }
        }
        return result;
    }
  • 问题2:决策树很容易理解,那么表达树是什么意思呢?详见链接1

  • 问题2解决方案:

  • 前缀表达式(前序遍历):/+A*CBD

  • 中缀表达式(中序遍历):A+B*C/D

  • 后缀表达式(后序遍历):ACB*+D/

  • 代码如下:

public class ExprTree {
    //最后访问头结点
    public BinaryTreeNode buildExprTree(char postfixExpr[],int size){
        LinkedList<BinaryTreeNode> stack=new LinkedList();
        BinaryTreeNode node=null;
        for(int i=0;i<size;i++){
            if(isOperateNum(postfixExpr[i])){
                node=new BinaryTreeNode();
                node.setLeft(null);
                node.setRight(null);
                node.setData(postfixExpr[i]);
                stack.push(node);
            }else{
                BinaryTreeNode leftChild=stack.pop();
                BinaryTreeNode rightChild=stack.pop();
                node =new BinaryTreeNode();
                node.setLeft(leftChild);
                node.setRight(rightChild);
                node.setData(postfixExpr[i]);
                stack.push(node);
            }
        }
        return stack.getLast(); 
    }
    
    //判断是否是操作数
    private boolean isOperateNum(char c){
        if(c=='/'||c=='+'||c=='*'||c=='-'){
            return false;
        }
        return true;
    }

}

其他(感悟、思考等)

在学习树的各种时,可以说是非常难的,但是看到更加优秀的人,创造出更加优秀的树,自己也要不断努力

参考资料