Java中用遞迴和迭代實現二叉樹的中序( InOrder )遍歷

jdon發表於2019-03-12

與陣列和連結串列不同,二叉樹有幾種遍歷方式。遍歷演算法大致分為深度優先和廣度優先遍歷演算法,這取決於演算法實際如何工作。顧名思義,深度優先在訪問同級別兄弟之前先向二叉樹縱深訪問,而廣度優先是先訪問同一級別中的所有節點然後再進入下一級別,因此它也被稱為級別順序遍歷。 PreOrder和InOrder樹遍歷演算法都是深度優先的,預序和中序演算法之間的唯一區別是訪問二叉樹的根,左節點和右節點的順序。

InOrder遍歷演算法首先訪問左節點,然後是root節點,最後是右節點。這與首先​​訪問根的預序遍歷不同。InOrder遍歷的一個重要特性是,如果給定的二叉樹是二叉搜尋樹,它將按排序順序列印節點。

請記住,如果左子樹中的所有節點都低於root並且右子樹中的所有節點都大於root,則二叉樹稱為二叉搜尋樹。

在示例中,使用二叉搜尋樹來演示InOrder樹遍歷以排序順序列印二叉樹的節點,並分享了這個問題的遞迴和迭代解決方案。從面試的角度來看,這非常重要。即使遞迴解決方案更容易,佔用更少的程式碼行,並且更具可讀性,您也應該知道如何在沒有Java遞迴的情況下遍歷二叉樹,以便在程式設計面試中做得更好。

Java中InOrder遍歷二叉樹 - 遞迴
由於二叉樹是遞迴資料結構,因此遞迴是解決基於樹的問題的最佳方法。以下是二叉樹InOrder遍歷的步驟:

1)訪問左節點
2)訪問root
3)訪問右節點

要實現此演算法,您可以使用InOrder遍歷編寫一個方法來遍歷二叉樹的所有節點,方法如下:

在inOrder(TreeNode節點)中編寫方法
檢查node == null,如果是,則返回,這是我們的基本情況。
呼叫inOrder(node.left)以遞迴方式訪問左子樹
列印節點的值
呼叫inOrder(node.right)以遞迴方式遍歷右子樹。

這將按照InOrder遍歷列印二叉樹的所有節點。如果二叉樹是二叉搜尋樹,則樹的所有節點將按排序順序列印。這是一種在Java中實現InOrder演算法的方法:

private void inOrder(TreeNode node) {
    if (node == null) {
      return;
    }

    inOrder(node.left);
    System.out.printf("%s ", node.data);
    inOrder(node.right);
  }


該方法是私有方法,因為它是透過另一個公共方法inorder()公開的,後者不需要來自客戶端的引數。這是一個facade模式的例子,它使客戶端的方法更簡單。遞迴演算法很容易理解,深入到左子樹,直到找到葉節點。一旦找到,遞迴堆疊就開始展開,列印節點資料並開始探索右子樹。

Java中InOrder遍歷二叉樹 - 迭代
您可以使用堆疊將遞迴的順序演算法轉換為迭代的順序演算法。。 沒有遞迴的解決方案雖然不容易閱讀,但也不是很難理解。 我們從根和程式開始,直到當前節點或Stack不為空。 我們開始從左子樹推節點,直到到達葉節點。 此時,我們pop()最後一個元素,列印它的值,並透過指定current=current.right開始探索右子樹。這將一直持續到堆疊變空為止,此時,二叉樹的所有元素都被訪問,樹遍歷完成。

 

  4
   / \
  2   5
 / \   \
1   3   6 

public void inOrderWithoutRecursion() {
    Stack nodes = new Stack<>();
    TreeNode current = root;

    while (!nodes.isEmpty() || current != null) {

      if (current != null) {
        nodes.push(current);
        current = current.left;
      } else {
        TreeNode node = nodes.pop();
        System.out.printf("%s ", node.data);
        current = node.right;
      }

    }
  }

Output
1 2 3 4 5 6 


因為我們的二叉樹是一個二叉搜尋樹,所以可以看到它們是按排序順序列印的。

Java中使用InOrder演算法遍歷二叉樹
這是我們在Java中使用InOrder演算法遍歷二叉樹的完整程式。類似於我們之前看到的preOrder示例,唯一的區別是root的訪問順序不是首先而是其次。 遞迴演算法很簡單,但迭代演算法有點難以理解。您必須記住,堆疊是一個後進先出的資料結構,您先推的節點將最後彈出。因為您需要按左--右的順序訪問節點,所以您必須先推左樹的節點,直到到達葉節點。然後列印該值並開始訪問右子樹。
我們使用了相同的BinaryTree和TreeNode類,在早期的基於樹的問題(例如計算葉節點)中,它用於表示二叉樹。二叉樹是常規二叉樹,TreeNode表示二叉樹中的節點。

import java.util.Stack;

/*
 * Java Program to traverse a binary tree 
 * using inorder traversal without recursion. 
 * In InOrder traversal first left node is visited, followed by root
 * and right node.
 * 
 * input:
 *     4
 *    / \
 *   2   5
 *  / \   \
 * 1   3   6
 * 
 * output: 1 2 3 4 5 6 
 */

public class InOrderTraversal {

  public static void main(String args) throws Exception {

    // construct the binary tree given in question
    BinaryTree bt = BinaryTree.create();

    // traversing binary tree using InOrder traversal using recursion
    System.out
        .println("printing nodes of a binary tree on InOrder using recursion");

    bt.inOrder();

    System.out.println(); // insert new line

    // traversing binary tree on InOrder traversal without recursion
    System.out
        .println("printing nodes of binary tree on InOrder using iteration");
    bt.inOrderWithoutRecursion();
  }

}

class BinaryTree {
  static class TreeNode {
    String data;
    TreeNode left, right;

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

    boolean isLeaf() {
      return left == null ? right == null : false;
    }

  }

  // root of binary tree
  TreeNode root;

  /**
   * traverse the binary tree on InOrder traversal algorithm
   */
  public void inOrder() {
    inOrder(root);
  }

  private void inOrder(TreeNode node) {
    if (node == null) {
      return;
    }

    inOrder(node.left);
    System.out.printf("%s ", node.data);
    inOrder(node.right);
  }

  public void inOrderWithoutRecursion() {
    Stack nodes = new Stack<>();
    TreeNode current = root;

    while (!nodes.isEmpty() || current != null) {

      if (current != null) {
        nodes.push(current);
        current = current.left;
      } else {
        TreeNode node = nodes.pop();
        System.out.printf("%s ", node.data);
        current = node.right;
      }

    }
  }

  /**
   * Java method to create binary tree with test data
   * 
   * @return a sample binary tree for testing
   */
  public static BinaryTree create() {
    BinaryTree tree = new BinaryTree();
    TreeNode root = new TreeNode("4");
    tree.root = root;
    tree.root.left = new TreeNode("2");
    tree.root.left.left = new TreeNode("1");

    tree.root.left.right = new TreeNode("3");
    tree.root.right = new TreeNode("5");
    tree.root.right.right = new TreeNode("6");

    return tree;
  }

}

Output
printing nodes of a binary tree on InOrder using recursion
1 2 3 4 5 6 
printing nodes of a binary tree on InOrder using iteration
1 2 3 4 5 6 


這就是如何使用InOrder遍歷演算法訪問二叉樹的所有節點。 正如我之前所說,InOrder是一種深度優先遍歷演算法,在訪問root之前首先探索左子樹,最後探索右子樹,因此它也被稱為LNR(左節點右)演算法。 inorder遍歷還有一個獨特的屬性,如果給定的二叉樹是二叉搜尋樹,它會按排序順序列印節點。 因此,如果必須按BST的排序順序列印所有節點,則可以使用此演算法。
 

相關文章