1. 程式人生 > >二叉樹三種遍歷遞迴及非遞迴實現

二叉樹三種遍歷遞迴及非遞迴實現

二叉樹的三種遍歷方式包括:

  1. 前序遍歷
  2. 中序遍歷
  3. 後序遍歷

三種遍歷的遞迴方法都非常好實現,而且簡單易懂。非遞迴實現也是通過使用來模擬遍歷的過程。順便提一句,能用遞迴做的,基本都能用棧來實現。前序遍歷和中序遍歷的非遞迴寫法相對比較簡單,只需要模擬遍歷過程即可。後序遍歷非遞迴寫法比較難,需要藉助一個輔助指標來記錄右子樹是否訪問過,以防止重複訪問陷入死迴圈。下面分別給出三種遍歷方法的遞迴非遞迴實現的程式碼:

前序遍歷

遞迴:

public void PreOrderTraversal(TreeNode root) {
    if (root == null) {
        return;
    }
    System.out.print(root.val);
    if (root.left != null) {
        PreOrderTraversal(root.left);
    }
    if (root.right != null) {
        PreOrderTraversal(root.right);
    }
}

非遞迴:

public void PreOrderTraversal2(TreeNode root){
    Stack<TreeNode> stack = new Stack<>();
    TreeNode node;
    if (root == null) {
        return;
    }
    stack.push(root);
    while (!stack.empty()) {
        node = stack.pop();
        System.out.print(node.val);
        if (node.right != null) {
            stack.push(node.right);
        }
        if (node.left != null) {
            stack.push(node.left);
        }//end if
    }
}

將根節點放入棧中,當棧不空時,取出棧頂元素x,訪問x的值,如果x的左孩子不為空,將其左孩子入棧;如果其右孩子不為空,將其右孩子入棧,直至棧空。

中序遍歷

遞迴:

public void InOrderTraversal(TreeNode root) {
    if (root == null) {
        return;
    }
    if (root.left != null) {
        InOrderTraversal(root.left);
    }
    System.out.print(root.val);
    if (root.right != null) {
        InOrderTraversal(root.right);
    }
}

非遞迴:
public void InOrderTraversal2(TreeNode root) {
    if (root == null) {
        return;
    }
    TreeNode node;
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    node = root.left;
    while ((node != null)||(!stack.empty())) {
        while (node != null) {
            stack.push(node);
            node = node.left;
        }
        node = stack.pop();
        System.out.print(node.val);
        node = node.right;
    }
}



1、先遍歷到二叉樹的最左結點

2、彈出棧頂元素x並訪問

3、考察x的右子樹是否為空,如果為空則執行2,否則將當前結點設為x的右子樹並執行1.

後序遍歷

遞迴:

public void PostOrderTraversal(TreeNode root) {
    if (root == null) {
        return;
    }
    if (root.left != null) {
        PostOrderTraversal(root.left);
    }
    if (root.right != null) {
        PostOrderTraversal(root.right);
    }
    System.out.print(root.val);
}

非遞迴:
public void PostOrderTraversal2(TreeNode root) {
    if (root == null) {
        return;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    TreeNode node = root.left;
    TreeNode lastVisit = null;
    while (node != null) {
        stack.push(node);
        node = node.left;
    }
    while (!stack.empty()) {
        node = stack.pop();
        if (node.right == null || node.right == lastVisit) {
            System.out.print(node.val);
            lastVisit = node;
        } else {
            stack.push(node);
            node = node.right;
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
        }
    }
}

後序遍歷非遞迴做法需要設定一個指標lastVisit指向上次輸出的元素。

1、從根節點開始遍歷到最左節點

2、當棧不空時彈出棧頂元素

3、如果棧頂元素x的右子樹為空或者x的右子樹等於lastVisit說明該右子樹已經訪問過,訪問當前節點x並將lastVisit指向x。

否則將x壓回棧中,並且將當前節點指向x的右子樹,執行步驟1.