二叉树系列 - 二叉树的前/中/后序遍历(非递归)

二叉树的遍历是二叉树中最最基础的部分。

 

这里整理二叉树不用递归实现三种顺序遍历的方式。

不用递归的话,一般需要栈来完成。当然线索二叉树(不需要栈或递归)也可以完成中序遍历,这种方式在这篇文章中已经讨论过。这里着重讨论使用栈的实现方式。

 

中序遍历

(1) 双while,第二个内层while是为了不断压入left child。

vector<int> inorderTraversal(TreeNode *root) {
        vector<int> v;
        if(!root) return v;
        TreeNode* tmp = root;
        stack<TreeNode* > st;
        while(tmp || !st.empty()){
            while(tmp){
                st.push(tmp);
                tmp = tmp -> left;
            }
            if(!st.empty()){
                tmp = st.top();
                st.pop();
                v.push_back(tmp -> val);
                tmp = tmp -> right;
            }
        }
        return v;
    }

Leet Code: Binary Tree Inorder Traversal  AC 8ms

更简单的去掉内层循环的写法,原理其实一样,唯一不同的就是高亮部分。

vector<int> inorderTraversal(TreeNode *root) {
        vector<int> v;
        if(!root) return v;
        TreeNode* tmp = root;
        stack<TreeNode* > st;
        while(tmp || !st.empty()){
            if(tmp){
                st.push(tmp);
                tmp = tmp -> left;
            }else{
                tmp = st.top();
                st.pop();
                v.push_back(tmp -> val);
                tmp = tmp -> right;
            }
        }
        return v;
    }

Leet Code: Binary Tree Inorder Traversal  AC 32ms

 

后序遍历

(1) 两栈实现法,一个栈st1用类似前序遍历的方式(细微的不同之处在于 left child先进栈),将所有输出存入另一个栈st2中。最后将st2的内容挨个输出就结了。

这种方式非常好理解,因为后序遍历就是那个改动后的前序遍历的倒序输出。st2的作用只有一个:就是逆序。因此如果输出结果是存在vector里的话,把结果直接reverse也可以。

 

(2) 一栈实现法,这种方式需要定义一个pre指针。

这种方式也很好理解,后序就是parent比孩子后输出,那么我们只要读到parent的时候,不忙着输出parent的值,而是让其留在栈内,把左右孩子继续往栈里压。

那啥时候才能输出parent呢?当发现左右孩子已经被输出的时候,就可以输出parent 了。pre就是用来记录最近输出的结点的。

vector<int> postorderTraversal(TreeNode *root) {
        std::vector<int> v;
        if(NULL == root) return v;
        std::stack<TreeNode*> st;
        TreeNode* pre = NULL;
        TreeNode* cur = NULL;
        
        st.push(root);
        while(!st.empty()){
            cur = st.top();
            if((NULL == cur -> right && NULL == cur -> left) 
            || (NULL != pre && (pre == cur -> right || pre == cur -> left))){
            //For each node, there will never be such case that one child is pre, one child is not yet traversed. Because both children are printed (or it's NULL) before stack.top == cur.
            //So if one child points to pre, that means current node can also be printed.
            //NULL != pre is used for the edge case that only two nodes: root contains one left node.
                st.pop();
                v.push_back(cur -> val);
                pre = cur;
            }else{
                if(NULL != cur -> right)
                    st.push(cur -> right);
                if(NULL != cur -> left)
                    st.push(cur -> left);
            }
        }
        return v;

 

posted on 2014-12-08 01:03  Felix Fang  阅读(1102)  评论(0编辑  收藏  举报

导航