Java面试--二叉树的遍历

二叉树的遍历

一、前序遍历

Java面试--二叉树的遍历

遍历顺序:先前序遍历树根,再前序遍历左子树,再前序遍历右子树

先遍历树根(A)--再遍历左子树(B)--再遍历左子树(D)--(D没有左子树了)再遍历右子树(E)--再遍历左子树(G)--(A没有左子树了)再遍历右子树(C)--(C没有左子树了)再遍历右子树(F) ;故顺序为 A-B-D-E-G-C-F;

 

二、中序遍历

Java面试--二叉树的遍历

遍历顺序:先中序遍历左子树,再遍历树根,再中序遍历右子树

先遍历左子树(D)--再遍历其父元素(B)--再遍历右子树(E)--再遍历左子树(G)--再遍历树根(A)--(A没有左子树了)再遍历右子树(C)--(C没有左子树了)再遍历右子树(F) ;故顺序为 D-B-G-E-A-C-F;

 

三、后序遍历

Java面试--二叉树的遍历

遍历顺序:先后序遍历左子树,再后序遍历右子树,再遍历树根

先遍历左子树(D)--再遍历左子树(G)--再遍历其父元素(E)--再遍历其父元素(B)--再遍历右子树(F)--在遍历其父元素(C)--再遍历s树根(A) ;故顺序为 D-G-E-B-F-C-A;

代码实现:

定义树节点 TreeNode.java

package interview.tree;

public class TreeNode {
  private final char value;
  private TreeNode left;
  private TreeNode right;
  private TreeNode parent;

  public TreeNode(char value) { //定义树的节点
    this.value = value;
    this.left = null;
    this.right = null;
    this.parent = null;
  } 

  public char getValue() {
    return value;
  }

  public TreeNode getLeft() {
    return left;
  }

  public void setLeft(TreeNode left) {
    this.left = left;
    if (this.left != null) {
      this.left.setParent(this);
    }
  }

  public TreeNode getRight() {
    return right;
  }

  public void setRight(TreeNode right) {
    this.right = right;
    if (this.right != null) {
      this.right.setParent(this);
    }
  }

  public TreeNode getParent() {
    return parent;
  }

  private void setParent(TreeNode parent) {
    this.parent = parent;
  }
}

定义二叉树 TreeCreater.java

package interview.tree;

public class TreeCreator {	//使用Node创建树
  public TreeNode createSampleTree() {
    TreeNode root = new TreeNode('A');
    root.setLeft(new TreeNode('B'));
    root.getLeft().setLeft(new TreeNode('D'));
    root.getLeft().setRight(new TreeNode('E'));
    root.getLeft().getRight().setLeft(new TreeNode('G'));
    root.setRight(new TreeNode('C'));
    root.getRight().setRight(new TreeNode('F'));
    return root;
  }

  public TreeNode createTree(String preOrder, String inOrder) {
    if (preOrder.isEmpty()) {
      return null;
    }

    char rootValue = preOrder.charAt(0);
    int rootIndex = inOrder.indexOf(rootValue);

    TreeNode root = new TreeNode(rootValue);
    root.setLeft(
        createTree(
            preOrder.substring(1, 1 + rootIndex),
            inOrder.substring(0, rootIndex)));
    root.setRight(
        createTree(
            preOrder.substring(1 + rootIndex),
            inOrder.substring(1 + rootIndex)));

    return root;
  }
}

定义遍历方法:TreeTraversal.java

package interview.tree;

public class TreeTraversal {

  public void preOrder(TreeNode root) {	//【前序遍历】
    if (root == null) {		//树为空的情况
      return;
    }
    System.out.print(root.getValue());	//先遍历树根
    preOrder(root.getLeft());	//再前序遍历左子树
    preOrder(root.getRight());	//再前序遍历右子树
  }

  public void inOrder(TreeNode root) {//【中序遍历】
    if (root == null) {
      return;
    }
    inOrder(root.getLeft());//先前序遍历左子树
    System.out.print(root.getValue());//再遍历树根
    inOrder(root.getRight());//再前序遍历右子树
  }

  public void postOrder(TreeNode root) {//【后序遍历】
    if (root == null) {
      return;
    }
    postOrder(root.getLeft());//先后序遍历左子树
    postOrder(root.getRight());//再后序遍历右子树
    System.out.print(root.getValue());//再遍历树根
  }

  public static void main(String[] args) {
    TreeCreator creator = new TreeCreator();
    TreeTraversal traversal = new TreeTraversal();

    
    TreeNode sampleTree = creator.createSampleTree();
    traversal.preOrder(sampleTree);
    System.out.println();
    traversal.inOrder(sampleTree);
    System.out.println();
    traversal.postOrder(sampleTree);
    System.out.println();

    
  }
}

输出:

Java面试--二叉树的遍历

例1. 由前序和中序遍历求出后序遍历

Java面试--二叉树的遍历

分析:

Java面试--二叉树的遍历

TreeTraversal.java

package interview.tree;

public class TreeTraversal {

  public void preOrder(TreeNode root) {	//【前序遍历】
    if (root == null) {		//树为空的情况
      return;
    }
    System.out.print(root.getValue());	//先遍历树根
    preOrder(root.getLeft());	//再前序遍历左子树
    preOrder(root.getRight());	//再前序遍历右子树
  }

  public void inOrder(TreeNode root) {//【中序遍历】
    if (root == null) {
      return;
    }
    inOrder(root.getLeft());//先前序遍历左子树
    System.out.print(root.getValue());//再遍历树根
    inOrder(root.getRight());//再前序遍历右子树
  }

  public void postOrder(TreeNode root) {//【后序遍历】
    if (root == null) {
      return;
    }
    postOrder(root.getLeft());//先后序遍历左子树
    postOrder(root.getRight());//再后序遍历右子树 
    System.out.print(root.getValue());//再遍历树根
  }

  public String postOrder(String preOrder, String inOrder) {	//【新增代码】例1,查找后续遍历
    if (preOrder.isEmpty()) {	//树为空时
      return "";
    }

    char rootValue = preOrder.charAt(0);	//拿出前序遍历的第一个点
    int rootIndex = inOrder.indexOf(rootValue);//在中序遍历中找到 A 即可分出左右树

    return  //不用建树,直接输出
        postOrder(
            preOrder.substring(1, 1 + rootIndex),//左子树前序遍历的区间
            inOrder.substring(0, rootIndex)) +	//左子树中序遍历的区间
        postOrder(
            preOrder.substring(1 + rootIndex),//右子树前序遍历的区间
            inOrder.substring(1 + rootIndex)) +//右子树中序遍历的区间
        rootValue;
  }

  public static void main(String[] args) {
    TreeCreator creator = new TreeCreator();
    TreeTraversal traversal = new TreeTraversal();

    System.out.println("Sample tree traversal");
    System.out.println("=====");
    TreeNode sampleTree = creator.createSampleTree();
    traversal.preOrder(sampleTree);
    System.out.println();
    traversal.inOrder(sampleTree);
    System.out.println();
    traversal.postOrder(sampleTree);
    System.out.println();

    System.out.println("=====");
    System.out.println("Creating tree from preOrder and inOrder");
    System.out.println("=====");
    TreeNode tree = creator.createTree("ABDEGCF", "DBGEACF");
    traversal.postOrder(tree);
    System.out.println();
    traversal.postOrder(creator.createTree("", "")); //空树
    System.out.println();
    traversal.postOrder(creator.createTree("A", "A"));//单节点
    System.out.println();
    traversal.postOrder(creator.createTree("AB", "BA"));//双节点
    System.out.println();

    System.out.println("=====");
    System.out.println("Generating postOrder directly");
    System.out.println("=====");
    System.out.println(
        traversal.postOrder("ABDEGCF", "DBGEACF"));
    System.out.println(
        traversal.postOrder("", ""));
    System.out.println(
        traversal.postOrder("A", "A"));
    System.out.println(
        traversal.postOrder("AB", "BA"));
  }
}

输出:

Java面试--二叉树的遍历

Java面试--二叉树的遍历

二、寻找中序遍历时的下一节点

Java面试--二叉树的遍历

将中序遍历由递归改为非递归,遍历顺序:

Java面试--二叉树的遍历 

寻找中序遍历时的下一节点用处:对搜索树做中序遍历,得到有序序列;

Java面试--二叉树的遍历

思路:

Java面试--二叉树的遍历

代码实现:InOrder.java

package interview.tree;

public class InOrder {	//定义中序遍历

  public TreeNode next(TreeNode node) {
    if (node == null) {
      return null;
    }

    if (node.getRight() != null) {	//右子树不为空,
      return first(node.getRight());//则返回右子树第一个节点
    } else {		//右子树为空,往上走
      while(node.getParent() != null
          && node.getParent().getRight() == node) {
        node = node.getParent();
      }
      // now we have:
      // node.getParent() == null
      // || node is left child of its parent
      return node.getParent();
    }
  }

  public TreeNode first(TreeNode root) {
    if (root == null) {
      return null;
    }

    TreeNode curNode = root;
    while(curNode.getLeft() != null) {
      curNode = curNode.getLeft();
    }
    return curNode;
  }

  public void traverse(TreeNode root) {
    for (TreeNode node = first(root);
        node != null;
        node = next(node)) {
      System.out.print(node.getValue());
    }
    System.out.println();
  }

  public static void main(String[] args) {
    TreeCreator creator = new TreeCreator();
    InOrder inOrder = new InOrder();

    TreeNode sampleTree = creator.createSampleTree();
    inOrder.traverse(sampleTree);

    inOrder.traverse(creator.createTree("", ""));
    inOrder.traverse(creator.createTree("A", "A"));
    inOrder.traverse(creator.createTree("AB", "BA"));
    inOrder.traverse(creator.createTree("ABCD", "DCBA"));
    inOrder.traverse(creator.createTree("ABCD", "ABCD"));
  }
}

输出:

Java面试--二叉树的遍历

例3

Java面试--二叉树的遍历

分析:后序遍历则最后一个为树根,二叉查找树中,左子树要比树根小,右子树要比树根大;所以序列中,前面一部分数字要比根要小,后面一部分数组要比根大,A 中 树根最大,则其没有右子树,只有左子树;B,3 和 5 是其右子树,1 是其左子树,但要先遍历左子树,故 B 不是;C 显然可以;D 与 A 相反,它只有右子树;故选 B

 

算法复杂度

代表最坏情况用时;

Java面试--二叉树的遍历

Java面试--二叉树的遍历

1.

Java面试--二叉树的遍历

2.

Java面试--二叉树的遍历

3.

Java面试--二叉树的遍历