[数据结构与算法]二叉树的前、中、后序非递归遍历以及层次遍历

前言:二叉树作为常见的数据结构,其重要性不言而喻。相信前、中、后序的递归遍历大家都已经非常熟悉,但很多场景是需要用到非递归的遍历(例如leetcode上的题目)。

前序遍历和中序遍历差不多,后序遍历稍微难一点,用点时间研究一下相信也能熟悉掌握。(整个流程建议结合画图会更好理解)

前序遍历:我们将会用到数据结构里面的栈。1:我们先从根节点开始一边沿着左子树的方向把每个结点压进栈中一边把每个结点一一输出,直到遇到null。2:接着我们弹出栈顶结点,检查该结点是否有右子树,如果有则把该右子树作为新的根节点重复1的操作,如果没有右子树则继续弹出栈顶直到栈为空。

直接上代码。

void preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* p = root;
        while(!st.empty()||p!=NULL)
        {
            while(p)
            {
                cout<<p->val<<" ";
                st.push(p);
                p=p->left;
            }
            if(!st.empty())
            {
                p = st.top();
                st.pop();
                p=p->right;
            }
        }
    }

中序遍历:整个思路和前序遍历一样,只是输出的位置不一样,按照前序遍历那样把一个个左子树压进栈里的时候先不要输出,等到遇到null的时候再把栈顶弹出并输出,之后同样检查栈顶是否存在右子树,如果存在则继续重复前面的操作,如果不存在则继续弹出栈顶进行检查。

void inorderTraversal(TreeNode* root) {
        TreeNode *p = root;
        stack<TreeNode*> s;
        while(p!=NULL||!s.empty())
        {
            while(p!=NULL)
            {
                s.push(p);
                p=p->left;
            }
            if(!s.empty())
            {
                p = s.top();
                cout<<p->val<<" ";
                s.pop();
                p=p->right;
            }
        }
    }

后序遍历:进行后序遍历,我们知道是先输出子结点再输出父节点。所以结点在两种情况下可以进行输出,1:该结点没有左右孩子,即该结点已经是叶子结点了。2:该结点有左右孩子,但是左右结点均已遍历过了。

void postorderTraversal(TreeNode* root) {
        stack<TreeNode*> sk;
        sk.push(root);
        TreeNode* cur;                   //当前结点
        TreeNode* pre = NULL;            //用于保存上一个遍历的结点
        while(!sk.empty())
        {
            cur = sk.top();
            if((cur->left==NULL&&cur->right == NULL)||
               (pre!=NULL&&(cur->left == pre||cur->right == pre)))    //若符合上述的两种情况其中的一种
            {
                cout<<cur->val<<" ";
                sk.pop();
                pre = cur;
            }
            else
            {
                if(cur->right) sk.push(cur->right);
                if(cur->left) sk.push(cur->left);
            }
        }
        return res;
    }

层次遍历:我们将会用到队列这种数据结构,思路是通过队列保存每一层的结点,我们每次遍历队列的时候,队列的大小为该层的结点数量。

void levelOrder(TreeNode* root) {
        queue<TreeNode*> q;
        q.push(root);            //第一次把根结点放进队列
        while(!q.empty())
        {
            int n = q.size();
            for(int i = 0;i<n;i++)      //队列的大小即该层次的结点数量
            {
                TreeNode* t = q.front();q.pop();   
                cout<<t->val<<" ";
                if(t->left) q.push(t->left);    
                if(t->right) q.push(t->right);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/Uupton/article/details/81031807