【问题标题】:How to do different traversals of an expression tree?如何对表达式树进行不同的遍历?
【发布时间】:2020-03-23 03:16:16
【问题描述】:

我试图弄清楚如何通过表达式树进行不同的遍历。例如,如果我输入“- + 10 * 2 8 3”,我希望它打印出该表达式的前缀、后缀和中缀版本。

我还需要通过后序遍历来计算表达式的结果,应该是evaluate函数。

但是,当我运行我的程序时,我只得到每个表达式的第一个字符。我对这些遍历如何工作的理解有误吗?

编辑:根据建议,我保存了构建树的结果并将 sc.next 更改为 sc.nextLine。

另外,每个方法都应该是递归的。

给定“- + 10 * 2 8 3”,预期的答案是:

prefix expression:
- + 10 * 2 8 3
postfix expression:
10 2 8 * + 3 -
infix expression:
( ( 10 + ( 2 * 8 ) ) - 3 )
Result = 23

我知道我没有为中缀表达式实现任何带括号的东西,但现在没关系。

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("Enter a prefix expression: ");

        Node root = buildTree(sc);

        System.out.println("prefix expression: ");
        infix(root);

        System.out.println("postfix expression: ");
        postfix(root);

        System.out.println("infix expression: ");   
        infix(root);

        System.out.print("Result = ");
        evaluate(root);
    }

    static Node buildTree(Scanner sc) {
        Node n = new Node(null);
        int i = 0;
        String prefixExpression  = sc.nextLine();
        String[] temp = prefixExpression.split(" ");

        if(n.isLeaf()) {

            n.value = temp[i];
            n.left = null;
            n.right = null;

            i++;

        }

        return n;
    }

    static void infix(Node node) {

        if(node.isLeaf()){
            System.out.println(node.value);
        }

        else {
            infix(node.left);
            System.out.println(node.value + " ");
            infix(node.right);
        }

    }

    void prefix(Node node) {

        if(node.isLeaf()){
            System.out.println(node.value);
        }
        else {
            switch(node.value) {
            case "+":
                System.out.print("+");
                break;
            case "-":
                System.out.print("-");
                break;
            case "*":
                System.out.print("*");
                break;
            case "/":
                System.out.print("/");
                break;
            }
        }

        prefix(node.left);
        System.out.print(" ");
        prefix(node.right);

    }

    static void postfix(Node node) {

        if(node.isLeaf()){
            System.out.println(node.value);
        }
        else {
            postfix(node.left);
            postfix(node.right);

            switch (node.value) {
            case "+":
                System.out.print("+");
                break;
            case "-":
                System.out.print("-");
                break;
            case "*":
                System.out.print("*");
                break;
            case "/":
                System.out.print("/");
                break;
            }
        }

    }

    public static int evaluate(Node node) {

        if(node.isLeaf()) {
            return Integer.parseInt(node.value);
        }

        else {
            int leftHandSide = evaluate(node.getLeft());
            int rightHandSide = evaluate(node.getRight());
            String operator = node.getValue();

            if("+".equals(operator)) {
                return leftHandSide + rightHandSide;
            }
            else if("-".equals(operator)) {
                return leftHandSide - rightHandSide;
            }
            else if("*".equals(operator)) {
                return leftHandSide * rightHandSide;
            }
            else if("/".equals(operator)) {
                return leftHandSide / rightHandSide;
            }
            else {
                System.out.println("Unexpected problem. Error.");
            }

            return 0;

        }
    }

}

这里是 Node.java,还有 getter 和 setter。

public class Node<E> {

    String value;
    Node<E> left;
    Node<E> right;

    Node(String value){
        left = null;
        right = null;
        this.value = value;
    }

    Node(String value, Node<E> left, Node<E> right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }

    boolean isLeaf() {

        return (left == null && right == null);

    }

【问题讨论】:

  • 我认为你的主要错误是使用 sc.next() 而不是 sc.nextLine()。
  • 其次,当您应该保存根节点时,您继续调用 buildTree()。
  • 另外,你需要在构建树的时候决定你的树节点应该如何排列,因为目前很难理解你的评估方法的目的?

标签: java


【解决方案1】:

编辑:

由于您的问题是“如何对表达式树进行不同的遍历?,我在您的代码中看到的问题是构建树(即buildTree() 方法)。

为了纠正这个问题,我使用buildExpressionTree(array) 方法将您的前缀输入转换为使用Stack 数据结构的表达式树。

表达式树的构造:

为了构建表达式树,我使用了堆栈。由于在您的情况下输入是前缀形式,因此通过输入表达式反向循环并对每个字符执行以下操作。

  1. 如果字符是操作数,则将其压入堆栈
  2. 如果字符是运算符,则从堆栈中弹出两个值,使其成为 子节点并再次推送当前节点。

最后只有栈的元素是表达式树的根。

此外,在打印不同的遍历时,您不需要所有这些 if 条件来检查不同的运算符。您可以简单地执行遍历,如下面的代码所示。

public static void main(String[] args) {

    Scanner sc = new Scanner(System.in);

    System.out.println("Enter a prefix expression: ");

    String prefixExpression  = sc.nextLine();
    String[] temp = prefixExpression.split(" ");
    Node n = null; 

    n = buildExpressionTree(temp);

    System.out.println("prefix expression: ");

    prefix(n);

    System.out.println();
    System.out.println("postfix expression: ");

    postfix(n);

    System.out.println();
    System.out.println("infix expression: ");

    infix(n);

    System.out.println();

    int result = evaluate(n);
    System.out.print("Result = "+ result);

}

static Node buildExpressionTree(String[] input) { 
    Stack<Node> st = new Stack(); 
    Node t, t1, t2; 
    // Traverse through every character of 
    // input expression 
    for (int i = (input.length-1); i >= 0; i--) { 

        // If operand, simply push into stack 
        if (isNumber(input[i])) { 
            t = new Node(input[i]); 
            st.push(t); 
        } else // operator 
        { 
            t = new Node(input[i]); 

            // Pop two top nodes 
            // Store top 
            t1 = st.pop();      // Remove top 
            t2 = st.pop(); 

            //  make them children 
            t.left = t1; 
            t.right = t2; 

            st.push(t); 
        } 
    } 

    t = st.peek(); 
    st.pop(); 

    return t; 
}

static boolean isNumber(String s) {

    boolean numeric = true;
    try {
        Integer num = Integer.parseInt(s);
    } catch (NumberFormatException e) {
        numeric = false;
    }
    return numeric;
}



static void infix(Node node) {

    if( null == node) {
        return;
    }
    infix(node.left);
    System.out.print(node.value + " ");
    infix(node.right);
}

static void prefix(Node node) {

    if( null == node) {
        return;
    }
    System.out.print(node.value+ " ");
    prefix(node.left);
    prefix(node.right);

}

static void postfix(Node node) {

    if( null == node) {
        return;
    }
    postfix(node.left);
    postfix(node.right);
    System.out.print(node.value+ " ");

}

public static int evaluate(Node node) {

    if(node.isLeaf()) {
        return Integer.parseInt(node.value);
    }

    else {
        int leftHandSide = evaluate(node.left);
        int rightHandSide = evaluate(node.right);
        String operator = node.value;

        if("+".equals(operator)) {
            return leftHandSide + rightHandSide;
        }
        else if("-".equals(operator)) {
            return leftHandSide - rightHandSide;
        }
        else if("*".equals(operator)) {
            return leftHandSide * rightHandSide;
        }
        else if("/".equals(operator)) {
            return leftHandSide / rightHandSide;
        }
        else {
            System.out.println("Unexpected problem. Error.");
        }

        return 0;

    }
}

输出:

Enter a prefix expression: 
- + 10 * 2 8 3
prefix expression: 
- + 10 * 2 8 3 
postfix expression: 
10 2 8 * + 3 - 
infix expression: 
10 + 2 * 8 - 3 
Result = 23 

【讨论】:

  • 输入前缀表达式与输出前缀表达式有何不同?运算符中的前缀或中缀表达式如何结束
  • 我和上面的用户有同样的问题。另外,您的意思是说“我确实需要所有这些 if 条件”,还是您的意思是“不需要”?
  • @user207421,感谢您提及这一点,但正如 OP 在问题中提到的那样“例如,如果我输入“ - + 10 * 2 8 3 ”,我希望它打印出前缀,后缀和该表达式的中缀版本。”,所以我认为 OP 只是想知道如何用他的代码打印不同的遍历。
  • @Tim Chaffin,您能否提及如果您的输入是“- + 10 * 2 8 3”,那么您期望前缀、后缀和中缀版本的输出是什么,所以我将编辑我的答案相应地?
  • @MOnkey,我已经更新了原始帖子以显示表达式的预期前缀、后缀和中缀版本。
猜你喜欢
  • 2015-09-11
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 2013-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多