二叉樹的前序中序后序遍歷總結

LeetCode有如下traversal的題目,這里只說普通遍歷:
Binary Tree Inorder Traversal
Binary Tree Level Order Traversal
Binary Tree Zigzag Level Order Traversal
Binary Tree Level Order Traversal II
Binary Tree Preorder Traversal
Binary Tree Postorder Traversal
Construct Binary Tree from Preorder and Inorder Traversal
Construct Binary Tree from Inorder and Postorder Traversal

基本思路有三種,第一種是trivial的遞歸,第二種是用stack,第三種是Morris

  • 用stack的方法分兩種,一種直觀的dfs像(1),一種用lastpop(2)或prev(3)記錄上一個節點以判斷遍歷路徑。
  • 方法(1)的思路是順著往left走直到遇見NULL,從stack彈出一個往right挪動,繼續往left走。
  • 方法(2)的思路是,每次循環分push left(left不為NULL并且從上往下遍歷),push right(right不為NULL并且right不是上次遍歷的店并且從左邊遍歷過來或者左邊為NULL),pop(其他情況)三種情況。
  • 方法(3)的思路是,每次循環分為from up(如果left不為NULL,push left否則right不為NULL,push right), from left(若right不為空push right),from right(其他情況)三種情況。

1.Discuss區的summary:

https://leetcode.com/discuss/71943/preorder-inorder-and-postorder-iteratively-summarization

  1. preorder

    public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    TreeNode p = root;
    while(!stack.isEmpty() || p != null) {
    if(p != null) {
    stack.push(p);
    result.add(p.val); // Add before going to children
    p = p.left;
    } else {
    TreeNode node = stack.pop();
    p = node.right;
    }
    }
    return result;
    }

  2. inorder

    public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    TreeNode p = root;
    while(!stack.isEmpty() || p != null) {
    if(p != null) {
    stack.push(p);
    p = p.left;
    } else {
    TreeNode node = stack.pop();
    result.add(node.val); // Add after all left children
    p = node.right;
    }
    }
    return result;
    }

3) postorder

public List<Integer> postorderTraversal(TreeNode root) {
    LinkedList<Integer> result = new LinkedList<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    TreeNode p = root;
    while(!stack.isEmpty() || p != null) {
        if(p != null) {
            stack.push(p);
            result.addFirst(p.val);  // Reverse the process of     preorder
            p = p.right;             // Reverse the process of     preorder
        } else {
            TreeNode node = stack.pop();
            p = node.left;           // Reverse the process of     preorder
        }
    }
    return result;
}

這個postorder用了取巧的方法,不如下面這種后序遍歷的實現,這個很舒服:

//后序遍歷的非遞歸實現
void BT_PostOrderNoRec(pBintree root)
{
    stack<pBintree> s;
    pBintree pre = NULL;
    pBintree top = NULL;
    while((root != NULL) || (!s.empty()))
    {
        if(root != NULL)
        {
            s.push(root);
            root = root->left;
        }
        else
        {
            top = s.top();
            if(top->right != NULL && top->right != pre)
                root = top->right;
            else
            {
                visit(top);
                pre = top;
                s.pop();
            }
        }
    }
}

2.lastpop方法
https://leetcode.com/discuss/9736/accepted-code-with-explaination-does-anyone-have-better-idea

  1. preorder

    void preorder_traversal_iteratively(TreeNode* root)
    {
    if (root == 0)
    return;
    stack<TreeNode> s;
    s.push(root);
    cout << root->val << ' '; // visit root
    TreeNode
    last_pop = root;
    while (!s.empty())
    {
    TreeNode* top = s.top();
    if (top->left != 0 && top->left != last_pop && top->right != last_pop) // push_left
    {
    s.push(top->left);
    cout << top->left->val << ' '; // visit top->left
    }
    else if (top->right != 0 && top->right != last_pop && (top->left == 0 || top->left == last_pop)) // push_right
    {
    s.push(top->right);
    cout << top->right->val << ' '; // visit top->right
    }
    else // pop
    {
    s.pop();
    last_pop = top;
    }
    }
    }

  2. inorder

    void inorder_traversal_iteratively(TreeNode* root)
    {
    if (root == 0)
    return;
    stack<TreeNode> s;
    s.push(root);
    TreeNode
    last_pop = root;
    while (!s.empty())
    {
    TreeNode* top = s.top();
    if (top->left != 0 && top->left != last_pop && top->right != last_pop) // push_left
    {
    s.push(top->left);
    }
    else if (top->right != 0 && top->right != last_pop && (top->left == 0 || top->left == last_pop)) // push_right
    {
    s.push(top->right);
    cout << top->val << ' '; // visit top
    }
    else // pop
    {
    s.pop();
    last_pop = top;
    if (top->right == 0)
    cout << top->val << ' '; // visit top
    }
    }
    }

  3. postorder

    void postorder_traversal_iteratively(TreeNode* root)
    {
    if (root == 0)
    return;
    stack<TreeNode> s;
    s.push(root);
    TreeNode
    last_pop = root;
    while (!s.empty())
    {
    TreeNode* top = s.top();
    if (top->left != 0 && top->left != last_pop && top->right != last_pop) // push_left
    {
    s.push(top->left);
    }
    else if (top->right != 0 && top->right != last_pop && (top->left == 0 || top->left == last_pop)) // push_right
    {
    s.push(top->right);
    }
    else // pop
    {
    s.pop();
    last_pop = top;
    cout << top->val << ' '; // visit top
    }
    }
    }

3.prev記錄方法 - 九章算法里的postorder做法

//Iterative
public ArrayList<Integer> postorderTraversal(TreeNode root) {
    ArrayList<Integer> result = new ArrayList<Integer>();
    Stack<TreeNode> stack = new Stack<TreeNode>();
    TreeNode prev = null; // previously traversed node
    TreeNode curr = root;

    if (root == null) {
        return result;
    }

    stack.push(root);
    while (!stack.empty()) {
        curr = stack.peek();
        if (prev == null || prev.left == curr || prev.right == curr) { // traverse down the tree
            if (curr.left != null) {
                stack.push(curr.left);
            } else if (curr.right != null) {
                stack.push(curr.right);
            }
        } else if (curr.left == prev) { // traverse up the tree from the left
            if (curr.right != null) {
                stack.push(curr.right);
            }
        } else { // traverse up the tree from the right
            result.add(curr.val);
            stack.pop();
        }
        prev = curr;
    }

    return result;
}

4.用兩個棧實現后序遍歷的方法
設置兩個棧stk, stk2;
將根結點壓入第一個棧stk;
彈出stk棧頂的結點,并把該結點壓入第二個棧stk2;
將當前結點的左孩子和右孩子先后分別入棧stk;
當所有元素都壓入stk2后,依次彈出stk2的棧頂結點,并訪問之。
第一個棧的入棧順序是:根結點,左孩子和右孩子;于是,壓入第二個棧的順序是:根結點,右孩子和左孩子。因此,彈出的順序就是:左孩子,右孩子和根結點。

void postOrder2(TreeNode *root) {
    if(root == NULL)
        return;

    stack<TreeNode *> stk, stk2;
    stk.push(root);
    while(!stk.empty()) {
        TreeNode *pNode = stk.top();
        stk.pop();
        stk2.push(pNode);
        if(pNode->left != NULL)
            stk.push(pNode->left);
        if(pNode->right != NULL)
            stk.push(pNode->right);
    }
    while(!stk2.empty()) {
        cout << stk2.top()->val << endl;
        stk2.pop();
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容