二叉树的遍历

90 阅读4分钟

二叉树的前中后序遍历(递归)

前序遍历

vector <int> res;

vector<int> main(TreeNode* root){
    dfs(root);
    return res;
}

void dfs(TreeNode* root){
    if (!root) return;
    res.push_back(root->val);
    dfs(root->left);
    dfs(root->right); 
}

中序遍历

vector <int> res;

vector<int> main(TreeNode* root){
    dfs(root);
    return res;
}

void dfs(TreeNode* root){
    if (!root) return;
    dfs(root->left);
    res.push_back(root->val);
    dfs(root->right); 
}

后序遍历

vector <int> res;

vector<int> main(TreeNode* root){
    dfs(root);
    return res;
}

void dfs(TreeNode* root){
    if (!root) return;
    dfs(root->left);
    dfs(root->right); 
    res.push_back(root->val);
}

二叉树的前中后序遍历(迭代)

前序遍历

  • 思路:二叉树的迭代遍历一般用栈来存储
    栈是先进后出的顺序,如果是前序遍历,输出为中->左->右,所以先将右儿子入栈,再将左儿子入栈
  • 模板解法:
    1. 初始化栈
    2. 当前节点赋值为根节点
    3. 将根节点和所有左孩子入栈并加入答案直至当前节点为空
    4. 每弹出一个栈顶元素就到达当前节点的右孩子
  • 代码模板
stack<TreeNode*> stk;
vector<int> res;
auto cur = root;
while (cur || stk.size()){
    while (cur){
        res.push_back(cur->val);
        stk.push(cur);
        cur = cur->left;
    }
    auto tmp = stk.top();
    stk.pop();
    cur = tmp->right;
}
  • 常规解法:
    1. 初始化栈
    2. 将根节点入栈
    3. 当栈不为空将栈顶元素记录弹出加入答案
    4. 如果元素有右儿子则将右儿子入栈,如果有左儿子则将左儿子入栈
  • 代码模板
stack<TreeNode*> stk;
vector<int> res;
if (root) stk.push(root);
while (stk.size()){
    auto c = stk.top();
    stk.pop();
    res.push_back(c->val);
    if (c->right) stk.push(c->right);
    if (c->left) stk.push(c->left);
}

中序遍历

  • 思路:与前序遍历的模板解法相似,区别是前序遍历中在找树的左底部的过程中记录答案,而中序遍历是找到左底部再开始记录答案
  • 模板解法:
    1. 初始化栈
    2. 当前节点赋值为根节点
    3. 将根节点和所有左孩子入栈直至当前节点为空
    4. 每弹出一个栈顶元素加入答案并到达当前节点的右孩子
  • 代码模板
stack<TreeNode*> stk;
vector<int> res;
auto cur = root;
while (cur || stk.size()){
    while (cur){
        stk.push(cur);
        cur = cur->left;
    }
    auto temp = stk.top();
    stk.pop();
    res.push_back(temp->val);
    cur = temp->right;
}

后序遍历

  • 思路:与前序遍历的模板解法类似
    栈是先进后出的顺序,如果是后序遍历,输出为左->右->中,和前序遍历中->左->右相比,可以在前序遍历的基础上将输入改为中->右->左,再将答案数组反转即为左->右->中
  • 模板解法:
    1. 初始化栈
    2. 当前节点赋值为根节点
    3. 将根节点和所有右孩子入栈并加入答案直至当前节点为空
    4. 每弹出一个栈顶元素就到达当前节点的左孩子
    5. 反转答案数组
  • 代码模板
stack<TreeNode*> stk;
vector<int> res;
auto cur = root;
while (cur || stk.size()){
    while (cur){
        stk.push(cur);
        res.push_back(cur->val);
        cur = cur->right;
    }
    auto temp = stk.top();
    stk.pop();
    cur = temp->left;
}
reverse(res.begin(), res.end());

二叉树的层序遍历

  • 思路:二叉树的前中后序遍历都是用深度优先搜索的方法(dfs)主要使用栈实现,层序遍历是广度优先搜索主要使用队列实现
  • 常规解法:
    1. 初始化队列
    2. 将根节点加入队列中
    3. 当队列不为空时,弹出队头元素,加入到答案中
    4. 如果左子树非空,左子树加入队列
    5. 如果右子树非空,右子树加入队列
  • 代码模板
queue<TreeNode*> q;
vector<int> res;
q.push(root);
while (q.size()){
    int n = q.size();
    for (int i = 0; i < n; i ++){
        auto cur = q.front();
        q.pop();
        res.push_back(cur->val);
        if (cur->left) q.push(cur->left);
        if (cur->right) q.push(cur->right); 
    }
}

二叉树有关的题目和二叉树遍历的关系

leetcode.226

  • 链接leetcode.cn/problems/in…
  • 解题方法:有三种方法解本道题
    从上到下遍历树的时候翻转左右节点->前序遍历
    遍历到树的叶子节点回溯的时候翻转左右节点->后序遍历
    遍历每一层,将每一层的左右节点翻转->层序遍历
  • leetcode解题代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        // 递归(终止条件)
        if (!root) return root;
        // 前序遍历(递归解法)
        swap(root->left, root->right);
        invertTree(root->left);
        invertTree(root->right);
        // 递归返回值
        return root;
    }
};

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        // 递归(终止条件)
        if (!root) return root;
        // 后序遍历(递归解法)
        invertTree(root->left);
        invertTree(root->right);
        swap(root->left, root->right);
        // 递归返回值
        return root;
    }
};

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        // 层序遍历模板
        queue<TreeNode*> q;
        if (root) q.push(root);
        while (q.size()){
            int n = q.size();
            for (int i = 0; i < n; i ++){
                auto c = q.front();
                q.pop();
                swap(c->left, c->right);
                if (c->left) q.push(c->left);
                if (c->right) q.push(c->right);
            }
        }
        return root;
    }
};

leetcode.589

  • 链接leetcode.cn/problems/n-…
  • 解题方法:前序遍历递归模板或前序遍历迭代常规解法模板
  • leetcode解题代码
class Solution {
public:
    vector<int> res;
    vector<int> preorder(Node* root) {
        // 递归终止条件
        if (!root) return res;
        // 前序遍历
        res.push_back(root->val);
        for (auto c: root->children) preorder(c);
        return res;
    }
};

class Solution {
public:
    vector<int> preorder(Node* root) {
        // 与前序遍历常规解法相似
        stack<Node*> stk;
        vector<int> res;
        if (root) stk.push(root);
        while (stk.size()){
            auto c = stk.top();
            stk.pop();
            res.push_back(c->val);
            for (int i = c->children.size() - 1; i >= 0; i --){
                stk.push(c->children[i]);
            }
        }
        return res;
    }
};

leetcode.590

  • 链接leetcode.cn/problems/n-…
  • 解题方法:后序遍历递归模板或后序遍历迭代常规解法模板
  • leetcode解题代码
class Solution {
public:
    vector<int> res;
    vector<int> postorder(Node* root) {
        // 递归终止条件
        if (!root) return res;
        // 后序遍历
        for (auto c: root->children) postorder(c);
        res.push_back(root->val);
        return res;
    }
};

class Solution {
public:
    vector<int> postorder(Node* root) {
        // 与后序遍历常规解法类似
        stack<Node*> stk;
        vector<int> res;
        if (root) stk.push(root);
        while (stk.size()){
            auto c = stk.top();
            stk.pop();
            res.push_back(c->val);
            for (int i = 0; i < c->children.size(); i ++){
                stk.push(c->children[i]);
            }
        }
        reverse(res.begin(), res.end());
        return res;
    }
};