树的前序 中序 后序遍历 总结

树的遍历总结

遍历方式概述

二叉树的遍历分为以下三种:

  • 先序遍历:遍历顺序规则为 先遍历根节点,再遍历左子树,最后遍历右子树(根-左-右)
  • 中序遍历:遍历顺序规则为 先遍历左子树,再遍历根节点,最后遍历右子树(左-根-右)
  • 后序遍历:遍历顺序规则为 先遍历左子树,再遍历右子树,最后遍历根节点(左-右-根)

1. 先序遍历

  • 先序遍历:遍历顺序规则为 先遍历根节点,再遍历左子树,最后遍历右子树(根-左-右)
1.1 前序遍历递归写法

Leetcode 144. 二叉树的前序遍历 递归写法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void dfs(TreeNode* root, vector<int> &res){
        // 如果根节点 为空,直接返回
        if(root == NULL) return ;
        // 根节点不为空,加入到遍历的数组中
        res.push_back(root->val);
        // 添加完根节点之后,遍历左节点
        dfs(root->left, res);
        // 添加完左节点之后,遍历右节点
        dfs(root->right, res);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if(root == NULL) return res;
        dfs(root, res);
        return res;
    }
};
执行结果

在这里插入图片描述

(./images/144%20result_preorderTraversal.png)]

1.2 前序遍历迭代写法1

Leetcode 144. 二叉树的前序遍历 迭代写法 1

关键代码

while(!st.empty()){
    		// 使用stack 存储右左节点 和遍历的左右顺序相反,先进后出
            TreeNode *temp = st.top();
            st.pop();
            if(!temp) continue;
            res.push_back(temp->val);
    		// 先后将 右左节点压入栈中
            if(temp->right) st.push(temp->right);
            if(temp->left) st.push(temp->left);
}

源代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        // 前序遍历  根左右
        vector<int> res;
        if(root == NULL) return res;
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty()){
            TreeNode *temp = st.top();
            st.pop();
            if(!temp) continue;
            res.push_back(temp->val);
            if(temp->right) st.push(temp->right);
            if(temp->left) st.push(temp->left);
        }
        return res;
    }

};
执行结果

在这里插入图片描述

1.3 前序遍历迭代写法2

Leetcode 144. 二叉树的前序遍历 迭代写法 2

关键代码

while(cur || !st.empty()){
    while(cur){
        st.push(cur);
        res.push_back(cur->val);
        cur=cur->left;
    }
    cur = st.top();
    st.pop();
    cur = cur->right;
}
return res;

源代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */

class Solution {
public:
    void dfs(TreeNode* root, vector<int> &res){
        // 如果根节点 为空,直接返回
        if(root == NULL) return ;
        // 根节点不为空,加入到遍历的数组中
        res.push_back(root->val);
        // 添加完根节点之后,遍历左节点
        dfs(root->left, res);
        // 添加完左节点之后,遍历右节点
        dfs(root->right, res);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        // 前序遍历  根左右
        vector<int> res;
        if(root == NULL) return res;
        stack<TreeNode*> st;
        TreeNode *cur= root;
        while(cur || !st.empty()){
            while(cur){
                st.push(cur);
                res.push_back(cur->val);
                cur=cur->left;
            }
            cur = st.top();
            st.pop();
            cur = cur->right;
        }
        return res;
    }

};
执行结果

在这里插入图片描述

2. 中序遍历

  • 中序遍历:遍历顺序规则为 先遍历左子树,再遍历根节点,最后遍历右子树(左-根-右)
2.1 中序遍历递归写法

LeetCode 94. 二叉树的中序遍历 递归写法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */


class Solution {
public:
    void dfs(TreeNode* root, vector<int> &res){
        // 如果根节点 为空,直接返回
        if(root == NULL){
            return ;
        }
        
        // 一直遍历 左节点  直到左节点为空,将根节点压入数组, 然后遍历右节点
        dfs(root->left, res);
        res.push_back(root->val);
        dfs(root->right, res);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        if(root == NULL) return res;
        dfs(root, res);
        return res;
    }
};
执行结果

在这里插入图片描述

2.2 中序遍历迭代写法

LeetCode 94. 二叉树的中序遍历 迭代写法

关键代码

while(cur || !st.empty()){ // 
            while(cur){  // 将根节点和所有左子树节点入栈
                st.push(cur);
                cur=cur->left;  
            }
            cur = st.top();  // 
            st.pop();
            res.push_back(cur->val);  
            cur = cur->right;            
}
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */


class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        // 中序遍历的顺序是 左中右  先进后出 使用栈来实现
        vector<int> res;
        if(root == NULL) return res;
        TreeNode *cur = root;
        stack<TreeNode*> st;
        
        while(cur || !st.empty()){ // 
            while(cur){  // 将根节点和所有左子树节点入栈
                st.push(cur);
                cur=cur->left;  
            }
            cur = st.top();
            st.pop();
            res.push_back(cur->val);  
            cur = cur->right;            
        }
        return res;
    }
};
执行结果

在这里插入图片描述

3. 后序遍历

  • 后序遍历:遍历顺序规则为 先遍历左子树,再遍历右子树,最后遍历根节点(左-右-根)
3.1 后序遍历递归写法

LeetCode 145. 二叉树的后序遍历 递归写法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void dfs(TreeNode* root, vector<int> &res){
        if(root == NULL) return ;

        dfs(root->left, res);
        dfs(root->right, res);
        res.push_back(root->val);

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

        dfs(root, res);
        return res;
    }
};
执行结果

在这里插入图片描述

3.2 后序遍历迭代写法

LeetCode 145. 二叉树的后序遍历 迭代写法

后续遍历的迭代代码是最难的一个。二叉树的后续遍历时最难的一种遍历方式,因为无法判定是否遍历过右子树,所以无法判断是否访问当前节点(只有访问过右子树后才能访问父节点)。

  • 问题:如何确定当前状态是访问了左子树后过来,还是访问了右子树后来的?

  • 如果是访问左子树后过来,那么要访问右子树,如果是访问右子树后过来,那么访问当前节点

  • 我们可以根据这一特性来分辨:
    如果是访问的右子树过来,那么上次访问结果是当前的右子树,通过记录上个访问的节点,即可解决该问题。

关键代码

 while(cur || !st.empty()){
     while(cur){
         st.push(cur);
         cur= cur->left;
     }
     cur = st.top(); // get the top element of stack
     st.pop();
     if((cur->right == NULL)|| (cur->right == pre_visit)){
         pre_visit = cur;    // 记录 上一个访问的节点是哪一个
         res.push_back(cur->val);
         cur = NULL;  // 下一步就是弹栈
     }
     else{
         st.push(cur);
         cur = cur->right;
     }
}
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void dfs(TreeNode* root, vector<int> &res){
        if(root == NULL) return ;
        dfs(root->left, res);
        dfs(root->right, res);
        res.push_back(root->val);

    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        if(!root) return res;
        stack<TreeNode*> st;
        TreeNode *cur = root;
        TreeNode * pre_visit;
        
        while(cur || !st.empty()){
            while(cur){
                st.push(cur);
                cur= cur->left;
            }
            cur = st.top(); // get the top element of stack
            st.pop();
            if((cur->right == NULL)|| (cur->right == pre_visit)){
                pre_visit = cur;    // 记录 上一个访问的节点是哪一个
                res.push_back(cur->val);
                cur = NULL;  // 下一步就是弹栈
            }
            else{
                st.push(cur);
                cur = cur->right;
            }
        }
        return res;

    }
};
执行结果

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C__Try

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值