二叉树的遍历

二叉树的遍历分为以下几种:
1. 层次遍历
2. 前序遍历
3. 中序遍历
4. 后序遍历

其中分为两类:层次遍历单作为一类,其他三种方式为另外一类。


  先总结前中后序这三种方法,如果有朋友恰好看到我的文章来找思路,我建议先别看代码的实现,人看了别人的代码自然而然地会有先入为主的感觉,说的不好听一点,叫背别人的代码,这是下意识地行为,所以还是一开始先别看为好。不知道我能不能讲清楚二叉树的道理,本人能力有限,抱歉。

  所以在这里推荐大家去看看leetcode,在探索栏目中有二叉树这个模块,感觉很不错

  首先大家想到的是递归的方式,这也是我们最多看到的。我们怎么想出递归这个思路呢?

  前中后序三种方法的特点在于单独看树的每个一小部分,它们都是一样的。我们把其他部分先不看,每个部分都是这样 一个自己本身,两个左右的子节点(子节点也可能不存在,这是边界情况)。将树拆分成一个一个这样的小块,最后将没有子节点的边界条件处理掉,这就是递归方法的主要思路。
在这里插入图片描述
  循环的方法主要思路在于使用一个容器来模拟递归。


前序遍历:

遍历首先访问根节点,然后遍历左子树,最后遍历右子树。

递归版本:
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        traversal(root, res);
        return res;
        
    }
    
    void traversal(TreeNode * root, vector<int> &res)
    {
        if(!root) return;
        traversal(root->left, res);
        res.push_back(root->val);
        traversal(root->right, res);
    }
};
循环版本:
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public: 
    vector<int> preorderTraversal(TreeNode* root) {
        treeNodes.push_back(root);
        while(treeNodes.size()) {
            TreeNode* tar = treeNodes.back();
            treeNodes.pop_back();
            if(!tar) continue;
            ret.push_back(tar->val);
            treeNodes.push_back(tar->right);
            treeNodes.push_back(tar->left);
        }
        return ret;
    }
private:
    vector<int> ret;
    vector<TreeNode*> treeNodes;
};

中序遍历:

中序遍历是先遍历左子树,然后访问根节点,然后遍历右子树。

循环版本:
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        tre.push(root);
        while(tre.size()) {
            TreeNode* top = tre.top();
            tre.pop();
            if(!top) continue;
            if(top->right || top->left) {
                tre.push(top->right);
                TreeNode* newOne = new TreeNode(top->val);
                tre.push(newOne);
                tre.push(top->left);    
            } else {           
                vec.push_back(top->val);
            }
            
        }
        return vec;
    }
private:
    vector<int> vec;
    stack<TreeNode*> tre;
};

   中后序遍历的循环版本和前序有所不同,在前序版本中,我们对于节点自身的值的处理是立即执行的,而在中后序中对于节点自身的处理是在处理过其他节点之后的,所以在这里我们构建一个没有子节点的新节点(边界情况)在存储节点本身的值。
   当然你也可以直接将节点本身的两个子节点指针设为NULL,然后置入stack,这样就不用创建新节点了,不过这样就破坏了原来的二叉树。

递归版本:
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        traversal(root, res);
        return res;
        
    }
    
    void traversal(TreeNode * root, vector<int> &res)
    {
        if(!root) return;
        traversal(root->left, res);
        res.push_back(root->val);
        traversal(root->right, res);
    }
};

后序遍历:

与前中序雷同,也就不在赘述。


层次遍历:

  层次遍历的思路有所不同:层序遍历是逐层遍历树结构

  在层次遍历中,我们选择队列而不是栈,因为栈在操作中我们会不断地压入新的节点,无法实现每次将一层的节点处理完,再处理下一层节点的需求。
  我选择创建tre, child_tre两个队列来存储节点,tre是我要处理的当前层次的节点,child_tre是tre中节点的子节点们。在每层处理完成后,我将交换child_tre和tre的值,如此循环,直到最后一次处理完时child_tre为空,交换后tre也就为空,然后退出while循环。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        tre.push(root);
        TreeNode* tar;
        vector<vector<int>> vec;
        if(!root) return vec;
        while(tre.size()){
            vec.push_back(vector<int>());
            while(tre.size()) {
                tar = tre.front();
                tre.pop();
                if(!tar) continue;
                vec.back().push_back(tar->val);
                if(tar->left)
                    child_tre.push(tar->left);
                if(tar->right)
                    child_tre.push(tar->right);
            }
            
            tre.swap(child_tre);
        }
        return vec;
    }
private: 
    queue<TreeNode*> tre, child_tre;
};

再次推荐leetcode的二叉树部分。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值