文章链接: 二叉树理论知识 递归遍历 迭代遍历 统一迭代 层序遍历

视频链接:递归遍历、迭代遍历1、迭代遍历2、层序遍历

题目链接: 144.前序遍历 94.中序遍历 145.后序遍历 102.二叉树的层序遍历

二叉树基础知识

代码随想录算法训练营第十一天| (二叉树)递归遍历、迭代遍历、统一迭代、层序遍历_迭代法

清晰版本地址: https://mubucm.com/doc/24WvH2u7pR

相关参考视频:( https://www.bilibili.com/video/BV1hw4m1q7DF?vd_source=65a224d3f97ae5a1002c0964faf8a876


用递归遍历:

分析步骤:

  1. 确定递归函数的参数和返回值;
  2. 确定终止条件;
  3. 确定单层递归的逻辑;

前序遍历:

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;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

中序遍历:

class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec){ // 直接修改,不返回
        if(cur == NULL) return;
        // 左中右
        traversal(cur->left, vec);
        vec.push_back(cur->val);
        traversal(cur->right, vec); 
    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

后序遍历:

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

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        Traversal(root, result);
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.


用迭代法遍历:

迭代法和递归的区别:

  1. 递归:就是在运行的过程中调用自己。
  2. 迭代法:也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。


前序遍历(迭代法)

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if(root == NULL) return result;
        st.push(root); // 先将根节点放入栈中
        while(!st.empty()){
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if(node->right) st.push(node->right); //先放右,再放左;出栈的时候才是“中左右”
            if(node->left) st.push(node->left);
        }
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.


中序遍历(迭代法)

无法通过前序遍历直接得到。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while(cur != NULL || !st.empty()){
            if(cur != NULL){
                st.push(cur);
                cur = cur->left; // 左(不为空就继续向左,直到最左)
            } else {
                cur = st.top();
                st.pop();
                result.push_back(cur->val); // 中
                cur = cur->right; // 右
            }
        }
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.


后序遍历(迭代法)

与前序遍历相似,注意最后要将结果翻转。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root){
        stack<TreeNode*> st; // 注意进栈的是树,不是数
        vector<int> result;
        if(root == NULL) return result;
        st.push(root);
        while(!st.empty()){
        // 左右中
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if(node->left) st.push(node->left);
            if(node->right) st.push(node->right);
        }
        reverse(result.begin(), result.end());
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.


统一迭代:

前面的迭代法中的前中后序遍历中的中序遍历与其他两个代码的书写有较大的区别,所以我们想:有没有一种办法能让三种遍历方式得到代码书写相似,即只改变遍历代码的顺序呢。接下来,就是要介绍”统一迭代法“。

前序遍历

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if(root != NULL) st.push(root);
        while(!st.empty()){
            TreeNode* node = st.top();
            if(node != NULL){
                st.pop();
                if(node->right) st.push(node->right); // 右
                if(node->left) st.push(node->left); // 左
                st.push(node); // 中
                st.push(NULL);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

中序遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if(root != NULL) st.push(root);
        while(!st.empty()){
            TreeNode* node = st.top();
            if(node != NULL){
                st.pop(); //将节点弹出,避免重复操作
                if(node->right) st.push(node->right); // 右节点加入栈中
                st.push(node); // 中节点入栈
                st.push(NULL); //加入空节点作为标记,为了等会记录节点的值
                if(node->left) st.push(node->left);
            } else {
                st.pop(); // 将空节点删除
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.


后序遍历

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root){
        stack<TreeNode*> st; // 注意进栈的是树,不是数
        vector<int> result;
        if(root != NULL) st.push(root);
        while(!st.empty()){
            TreeNode* node = st.top();
            if(node != NULL){
                st.pop(); 
                st.push(node); // 中
                st.push(NULL);

                if(node->right) st.push(node->right); // 右
                if(node->left) st.push(node->left); // 左
            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.


层序遍历:

相当于图论中的"广度优先搜索"(BFS)。

队列实现。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*>que;
        vector<vector<int>> result;
        if(root != NULL) que.push(root);
        while(!que.empty()){
            int size = que.size();
            vector<int> vec;
            for(int i = 0; i < size; i++){ // 不能用que.size(),因为que.size是不断变化的
                TreeNode* node = que.front();
                que.pop();
                vec.push_back(node->val);
                
                // 将左、右孩子加入队列中,以进行下一层遍历
                if(node->left) que.push(node->left); 
                if(node->right) que.push(node->right);
            }
            result.push_back(vec);
        }
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.


今日收获:

今日学习了二叉树的BFS和DFS。DFS包括前中后序遍历(递归法、迭代法、统一迭代法);BFS包括层序遍历。