构建一颗表达式树, 本质仍是一颗二叉树,可在叶子节点存放操作数, 双亲结点放运算符,一棵子树又可以看作另一叶子节点。 以类似于霍夫曼编码的方式将栈中的结点组织起来,为了简化操作,以空格分割的字符串作为一个Token,首先将中缀表达式转换为后缀表达式。

  • 实现思路, 数字直接输出, 碰到右圆括号, 不断弹栈并直到找到匹配的左圆括号.
  • 看到其他运算符, 弹栈至找到低优先级的运算符, 该过程要保留左圆括号.
import java.util.HashMap;

public class PostfixConversion {
  public static final Integer BUF_SIZE = 100;
  /* 低优先级运算符 */
  public static final Integer LOW_PRI_OP = 1;
  /* 高优先级运算符 */
  public static final Integer HIGH_PRI_OP = 2;
  /* 圆括号 */
  public static final Integer PAREN = 3;

  /* 运算符对照表 */
  public static HashMap<String, Integer> opTable = new HashMap<>();
  static {
    opTable.put("+", LOW_PRI_OP);
    opTable.put("-", LOW_PRI_OP);
    opTable.put("*", HIGH_PRI_OP);
    opTable.put("/", HIGH_PRI_OP);
    opTable.put("(", PAREN);
    opTable.put(")", PAREN);
  }
  /* 泛型栈的简单实现 */
  private static class Stack<T> {
    int top = 0;
    T[] buf;
    Stack() {
      buf = (T[])new Object[BUF_SIZE];
    }
    public void push(T item) {
      if (item == null)
        return;
      buf[top++] = item;
    }
    public T pop() {
      return (T)((top > 0) ? buf[--top] : null);
    }
  }
  /**
   * 将中缀表达式转换为后缀表达式
   * @param infix 以空格分割的中缀表达式
   * @return 逆波兰表达式
   */
  static String convert(String infix) {
    String[] input = infix.split(" ");
    StringBuilder output = new StringBuilder();
    String temp;
    Stack<String> opStack = new Stack<>(); // 运算符栈
    for (String str: input)
      if ( opTable.containsKey(str) ) { // 如果是运算符,进行处理
        Integer priority = opTable.get(str); // 获取当前运算符优先优先级
        if (priority == PAREN && ")".equals(str)) {
          // 输出运算符栈中与对应圆括号之间所有运算符
          while (!"(".equals(temp = opStack.pop()))
            output.append(temp).append(" ");
        } else {
          // 输出优先级比当前高或相等的运算符,并把当前运算符压入栈中
          for (temp = opStack.pop(); temp != null &&
              opTable.get(temp) != PAREN &&
              opTable.get(temp) >= priority; temp = opStack.pop())
            output.append(temp).append(" ");
          opStack.push(temp);
          opStack.push(str);
        }
      } else    // 不是运算符直接输出
        output.append(str).append(" ");

    // 取出运算符栈中所有运算符
    while (( temp = opStack.pop()) != null)
      output.append(temp).append(" ");
    return output.toString();
  }
  /* TODO 
  private static class Node<T> {}
  static Node<String> expTree(String postfix) {}
  */
}
  • 有了后缀表达式,剩下只要构建树就可以了,继续沿用上面的类
/* 简单的二叉树实现 */
private static class <T> {
  T element;
  Node<T> left;
  Node<T> right;
  Node(T theElement) {
    this(theElement, null, null);
  }
  Node(T theElement, Node<T> lt, Node<T> rt) {
    element = theElement;
    left = lt;
    right = rt;
  }
}
/**
 * 将后缀表达式转换为表达式树
 * @param postfix 要转换的后缀表达式
 */
static Node<String> expTree(String postfix) {
  String[] token = postfix.split(" ");
  Stack<Node<String>> nodeStack = new Stack<>(); //树的结点栈
  for ( String str: token) {
    if (opTable.containsKey(str)) {
      Node<String> rightNode = nodeStack.pop();
      Node<String> leftNode = nodeStack.pop();
      Node<String> tmp = new Node<>(str, leftNode, rightNode);
      nodeStack.push(tmp);
    } else
      nodeStack.push(new Node<String>(str));
  }
  return nodeStack.pop();
}
private static <T> void print(Node<T> t, int indent) {
  if (t != null) {
    print(t.right, indent + 1);
    for (int i= 0; i < indent; i++)
      System.out.print("   ");
    System.out.println(t.element);
    print(t.left, indent + 1);
  }
}
public static void main(String[] args) {
  System.out.println("=== inorder: ===");
  String infix = "( a + ( b * c ) ) + ( ( ( d * e ) - f ) * g )";
  System.out.println(infix+"\n=== postoreder: ===");
  String postfix = convert(infix);
  System.out.println(postfix+"\n=== 表达式树: ===");
  Node<String> expTree = expTree(postfix);
  print(expTree, 0);
}
/*
 * output:
 * =>  === inorder: ===
 * =>  ( a + ( b * c ) ) + ( ( ( d * e ) - f ) * g )
 * =>  === postoreder: ===
 * =>  a b c * + d e * f - g * + 
 * =>  === 表达式树: ===
 * =>        g
 * =>     *
 * =>           f
 * =>        -
 * =>              e
 * =>           *
 * =>              d
 * =>  +
 * =>           c
 * =>        *
 * =>           b
 * =>     +
 * =>        a
 * =>  
 */