二叉树 | 二叉树的前序/中序/后序遍历的非递归实现

问题:二叉树的前序遍历

问题链接
在这里插入图片描述

解题思路

前序遍历按照根、左、右的顺序访问节点,非递归实现要使用到栈,我们先访问本节点,然后将本节点入栈,用于下次遍历此节点的右子树,然后继续访问本节点的左孩子,重复,直到本节点的左孩子为NULL,此时就可以退栈,直到栈顶节点的右孩子不为空,下一个要访问的节点就是栈顶元素的右孩子,将栈顶元素弹出。如果找不到则遍历结束

C++代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*>s;
        vector<int>pre;
        while(root){
            while(root){
                pre.push_back(root->val);//访问本节点
                s.push(root);//将本节点入栈,用于下次访问其右子树
                root = root->left;//访问左孩子
            }
            //退栈直到栈顶节点有右孩子
            while(!s.empty() && !s.top()->right) s.pop();
            if(s.empty()) break;//如果栈空就退出
            root = s.top()->right;
            s.pop();
        }
        return pre;
    }
};

问题:二叉树的中序遍历

问题链接
在这里插入图片描述

解题思路

中序遍历的顺序是左、根、右,中序遍历的非递归实现和前序遍历差不多,只是在中序遍历中我们先不要访问本节点,直接入栈,继续访问本节点的左孩子,当回退时再访问本节点。

C++代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>inorder;
        stack<TreeNode*>s;
        while(root){
            while(root){
            //先将本节点入栈,等它的左子树被访问完了再访问它
                s.push(root);
                root = root->left;//继续访问它的左孩子
            }
            while(!s.empty()){//如果栈不空
           //栈顶元素的左子树都被访问了,接下来访问栈顶元素
                TreeNode *tmp  =  s.top();
                s.pop();//退栈
                inorder.push_back(tmp->val);
           //如果栈顶元素有右子树,则遍历它的右子树
                if(tmp->right){
                    root = tmp->right;
                    break;
                }
            }
        }
        return inorder;
    }
};

问题:二叉树的后序遍历

问题链接
在这里插入图片描述

解题思路

二叉树后序遍历的非递归实现和前两种遍历的实现不同,由于访问的顺序是左、右、根,只有当本节点的左子树和右子树被访问后才能访问本节点,我们用映射map记录每个节点入栈的次数,出栈时,当节点的入栈次数为1,说明本节点的左子树被访问完了,但是其右子树还没有被访问,此时不能访问本节点,让本节点再次入栈,访问本节点的右子树,出栈时,当节点的入栈次数为2,说明本节点的左右子树都被访问完了,可以访问本节点。

C++代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        map<TreeNode*,int>dict;//记录每个节点入栈的次数
        stack<TreeNode*>s;
        vector<int>post;
        while(root){
            while(root){
                s.push(root);//先不访问,直接入栈
                dict[root]++;//节点root入栈的次数加一
                root = root->left;//继续访问左子树
            }
            while(!s.empty()){
                TreeNode *tmp = s.top();
                s.pop();
                //如果本节点入栈过两次则访问
                if(dict[tmp] == 2) 
                    post.push_back(tmp->val);
                else{//本节点的右子树还没有被访问
                    s.push(tmp);//再次入栈
                    dict[tmp]++;//入栈次数加一
                    root = tmp->right;//访问本节点的右子树
                }
                if(root) break;
            }
        }
        return post;
    }
};
发布了860 篇原创文章 · 获赞 270 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/SongBai1997/article/details/104709624