AcWing
  • 首页
  • 题库
  • 题解
  • 分享
  • 问答
  • 活动
  • 应用
  • 吐槽
  • 登录/注册

二叉树的4种遍历

作者: 作者的头像   well188 ,  2021-02-06 11:48:09 ,  阅读 80


2


二叉树以根节点的位置不同,定义了3种遍历方式。
1、先序遍历:根节点在开始位置,根节点、左节点、右节点。《栈》
2、中序遍历:根节点在中间位置,左节点、根节点、右节点。《栈》
3、后序遍历:根节点在最后位置,左节点、右节点、根节点。《栈》
其他遍历
4、层次遍历:以根节点为第一层,一层层遍历。《队列》

遍历二叉树是理解递归的重要方法,二叉树是一种最简单的自相似树,反复重复自己形成的树。除了用递归的写法,还有用栈的写法也要掌握,因为,用栈的写法详细的解释了,递归的工作原理。递归就是系统使用一个隐藏的栈辅助。用栈的写法可以详细的了解递归内部的运作原理,更加清晰明了递归的运行原理。

无论递归还是迭代,每个节点都是作为当前根节点来处理的。所以在函数代码中只有一次push_back

root=root->right 迭代写法中这循环中的最后一句,相当于递归传参 digui(root->right)

先序遍历

递归写法

class Solution {
public:
    void preorder(TreeNode *root, vector<int> &res) {
        if (root == NULL) return;//如果root空就退出
        res.push_back(root->val);//把root放入res
        preorder(root->left, res);//递归左节点
        preorder(root->right, res);//递归右节点
    }

    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;//定义返回容器res
        preorder(root, res);//递归
        return res;//返回
    }
};

栈写法

栈顶节点就是我们需要的最近的父节点。

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;//定义容器
        if (root == NULL) return res;//root空就返回
        stack<TreeNode*> stk;//定义栈容器
//root写前面,可省略第5行
        while (root!=NULL || !stk.empty()) {//root不空或stk不空就循环
            while (root != NULL) {//root不空循环
                res.push_back(root->val);//把root的值放入res
                stk.push(root);//把root节点放入栈中
                root = root->left;//移动到左节点
            }
            root = stk.top();//栈顶节点存入root,栈顶就是最近的父节点
            stk.pop();//弹出栈顶节点
            root = root->right;//移动到右节点
        }
        return res;//返回
    }
};

中序遍历

递归写法

class Solution {
public:
    void inorder(TreeNode* root, vector<int>& res) {
        if (root==NULL) return;//root空就退出
        inorder(root->left, res);//移动到左节点
        res.push_back(root->val);//把当前值放入res
        inorder(root->right, res);//移动到右节点
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        inorder(root, res);
        return res;
    }
};
//当前节点的下一层某个分叉执行完毕后,会返回到上一层执行剩余没有执行的分叉上去执行。

栈写法

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;//定义返回容器res
        if(root==NULL) return res;//若root空返回res,注意这句可省略
        stack<TreeNode*> stk;//定义栈
        while (root != NULL || !stk.empty()) {//若root不空或stk不空就循环
            while (root != NULL) {//root不空就循环
                stk.push(root);//放入栈
                root = root->left;//移动到左节点
            }
            root = stk.top();//取出栈顶节点放入root
            stk.pop();//弹出栈顶节点
            res.push_back(root->val);//放入节点值到res
            root = root->right;//移动到右节点
        }
        return res;//返回
    }
};

后序遍历

递归写法

class Solution {
public:
    void postorder(TreeNode *root, vector<int> &res) {
        if (root == NULL) return;//root空就退出
        postorder(root->left, res);//移动到左节点
        postorder(root->right, res);//移动到右节点
        res.push_back(root->val);//当前节点的值放入res
    }
    //当前子节点执行完毕后,返回到父节点执行剩余的子节点。

    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        postorder(root, res);
        return res;
    }
};

栈写法

//后序遍历中,每个根会被访问2次,第一次时右节点是新点,访问右节点。
//第2次时,右节点是旧点,就访问根。
//访问方法是:先尽可能的访问最左侧的左节点,然后通过根访问右节点,再从右节点回到根节点。
//放:放入容器,存:存入变量
class Solution {
    public:
        vector<int> postorderTraversal(TreeNode *root) {
            vector<int> res;//定义存储容器
            if (root == NULL) return res;//如果root为空,返回res,这句可以省略
            stack<TreeNode*> stk;//定义栈
            TreeNode *prev = NULL;//存放上一个访问的节点
            while (root != NULL || !stk.empty()) {//如果root不空或stk不空就循环
                while (root != NULL) {//如果root不空循环
                    stk.push(root);//把root放入stk
                    root = root->left;//移动到左节点
                }//root为空时退出循环
                root = stk.top();//把栈顶的节点存入root
                stk.pop();//弹出栈顶
                if (root->right == NULL || root->right == prev) {//访问根时需要执行的代码
                    res.push_back(root->val);//把root放入res
                    prev = root;//把当前点存入prev作为父节点的标记
                    root = NULL;//把root置空,第2个while循环不必执行
                } else {//访问右节点需要执行的代码
                    stk.push(root);
                    root = root->right;
                }
            }
            return res;//返回res
        }
};

层次遍历《使用队列》

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector <vector <int> > res;
        if (root==NULL) return res;//如果root空则返回
        queue <TreeNode*> q;//定义队列
        q.push(root);//把第一个放入队列
        while (!q.empty()) {//队列不空就循环
            int n = q.size();//获取当前层的大小
            res.push_back(vector <int> ());//放入一个空的vector
            for (int i = 0; i < n; i++) {//处理当前层的节点
                TreeNode *node = q.front(); q.pop();//队列头存入node,弹出头
                res.back().push_back(node->val);//把当前节点放入res
                if (node->left!=NULL) q.push(node->left);//如果左端点不空,则移动到左端点
                if (node->right!=NULL) q.push(node->right);//如果右端点不空,则移动到右端点
            }
        }

        return res;//返回
    }
};

0 评论

你确定删除吗?

© 2018-2021 AcWing 版权所有  |  京ICP备17053197号-1
联系我们  |  常见问题
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标
请输入绑定的邮箱地址
请输入注册信息