二叉树的遍历方式

理解并熟练运用二叉树的遍历方式,对理解二叉树相关题目非常重要,尤其是使用递归解决二叉树的题目思路。很多二叉树的题目其最基础的地方都是在与遍历方式的选择。

理解二叉树的递归遍历,是理解回溯的基础。

二叉树的三种基本遍历方式

根据中间节点被访问的顺序,把二叉树的遍历分为前序、中序、后序三种,这三种遍历方法又称深度优先遍历 (DFS)

前序遍历

中左右

中序遍历

左中右

二叉搜索树的中序遍历结果是升序序列

后序遍历

左右中

后序遍历的递归实现其实就是一种回溯的利用

递归实现

递归遍历代码非常简洁,只需要稍微改变一下代码顺序就能实现三种遍历方式。

前序遍历

class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        vec.push_back(cur->val);    // 中
        traversal(cur->left, vec);  // 左
        traversal(cur->right, vec); // 右
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
};

leetcode 144. 二叉树的前序遍历

中序遍历

void traversal(TreeNode* cur, vector<int>& vec) {
    if (cur == NULL) return;
    traversal(cur->left, vec);  // 左
    vec.push_back(cur->val);    // 中
    traversal(cur->right, vec); // 右
}

leetcode 94. 二叉树的中序遍历

后序遍历

void traversal(TreeNode* cur, vector<int>& vec) {
    if (cur == NULL) return;
    traversal(cur->left, vec);  // 左   
    traversal(cur->right, vec); // 右
    vec.push_back(cur->val);    // 中
}

145. 二叉树的后序遍历

迭代实现

递归的本质就是通过栈的调用来实现的,借助栈数据结构我们可以通过迭代来遍历

前序遍历

前序遍历节点在出栈的同时访问,实现起来非常简单

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> sta;
        if (root != nullptr) sta.push(root);
        while (!sta.empty()) {
            TreeNode* cur = sta.top();              
            sta.pop();                              
            res.push_back(cur->val);                //中
            if (cur->right) sta.push(cur->right);   //右节点先入栈后访问
            if (cur->left) sta.push(cur->left);     //左节点后入栈先访问
        }
        return res;
    }
};

中序遍历

中序遍历实现起来要复杂一些,因为中序遍历栈的操作和节点的访问操作不是同时的,所以需要一个额外的指针来控制节点的遍历

主要区别在于:

  1. 循环条件变化:由于增加了一个指针,循环的条件变成栈不为空或者指针不为空,只有两者都为空时才说明全部遍历完了
  2. 额外指针作用:指针优先将左节点入栈,直到左节点为空,这时候通过栈操作来访问节点,然后指针指向出栈节点的右节点,重复以上操作。
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> sta;
        TreeNode* cur = root; //添加一个用来遍历的额外指针
        while (!sta.empty() || cur != NULL) {
            if (cur != NULL) {      //遍历的节点不为空就加入栈中
                sta.push(cur);
                cur = cur->left;             //左
            } else {  //cur 为空,sta不为空
                TreeNode* tmp = sta.top();
                sta.pop();              
                res.push_back(tmp->val);    //中   
                cur = tmp->right;           //右
            }
        }
        return res;
    }
};

后序遍历

  • 方法一:在先序遍历的基础上更改,后序遍历是左右中,先序是中左右

    中左右 ---> 中右左 ---> 左右中

    经过两次变化

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> sta;
        if (root == nullptr) return res;
        sta.push(root);
        while (!sta.empty()) {
            TreeNode* node = sta.top();
            sta.pop();
            res.push_back(node->val);
            if (node->left) sta.push(node->left);		//变化一:节点入栈顺序翻转
            if (node->right) sta.push(node->right);
        }
        reverse(res.begin(), res.end());				//变化二:最终结果翻转
        return res;
    }
};
  • 方法二:方法一比较投机取巧同时非常好理解,方法二用了和中序遍历迭代法相似的思路——增加两个指针

    在返回根节点时,需要知道是从右节点返回的,还是从左节点返回点,所以还需要一个辅助指针指向上一个访问的节点

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> sta;
        TreeNode* cur = root;       //遍历指针
        TreeNode* pre = nullptr; //辅助指针,指向上一次访问过的节点
        while (cur || !sta.empty()) {
            if (cur) {
                sta.push(cur);
                cur = cur->left;                //左
            } else {
                cur = sta.top();
                if(cur->right && cur->right!=pre) {   //当右节点还没被访问时
                    cur = cur->right;           //右
                } else {                                //右节点被访问过了
                    res.push_back(cur->val);   //中
                    sta.pop();                    
                    pre = cur;              //更新辅助指针
                    cur = nullptr;          
                }
            }
        }
        return res;
    }
};

层次遍历(BFS)

前面实现二叉树的前、中、后序遍历时都是使用了栈的数据结构,以二叉树的深度为优先进行遍历。

在实现层次遍历,也就是二叉树的广度优先遍历时(BFS),需要使用队列。

下面时 BFS 的通用模板

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {       
        vector<vector<int>> res;
        queue<TreeNode*> que;
        if (root != nullptr) {
            que.push(root);
        }
        while(!que.empty()) {
            //记录每层输出的个数
            int size = que.size();
            vector<int> row;		//row 记录每层输出结果
            while(size--) {
                TreeNode* tmp = que.front();
                que.pop();
                if(tmp->left) que.push(tmp->left);
                if(tmp->right) que.push(tmp->right);
                row.push_back(tmp->val);
            }
            res.push_back(row);
        }
        return res;
    }
};

102. 二叉树的层序遍历

posted @   油虾条  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示