二叉树-遍历(递归+非递归)

1.二叉树的遍历方式

对于一棵二叉树一共有四种遍历方式。分别是:前序遍历、中序遍历、后序遍历和层序遍历
前序遍历:根左右的顺序
中序遍历:左根右的顺序
后序遍历:左右根的顺序
层序遍历:一层一层的遍历也叫广度优先遍历
例如:
在这里插入图片描述
前序遍历:4 2 5 6 1 3
中序遍历:5 2 6 4 1 3
后序遍历:5 6 2 3 1 4
层序遍历:4 2 1 5 6 3

2.递归

2.1前序遍历

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

2.2中序遍历

class Solution {
public:
    void in(TreeNode* root,vector<int>&result){
        if(root==nullptr){
            return;
        }
        in(root->left,result);//左
        result.push_back(root->val);//根
        in(root->right,result);//右
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        in(root,result);
        return result;
    }
};

2.3后序遍历

class Solution {
public:
    void post(TreeNode* root,vector<int>&result){
        if(root==nullptr){
            return;
        }
        post(root->left,result);//左
        post(root->right,result);//右
        result.push_back(root->val);//根
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        post(root,result);
        return result;
    }
};

2.4层序遍历

class Solution {
public:
    void Order(TreeNode* cur,int depth,vector<vector<int>>& result){
        if(cur==nullptr){
            return;
        }
        if(result.size()==depth){
            result.push_back(vector<int>{});//为即将放入的元素申请空间
        }
        result[depth].push_back(cur->val);
        Order(cur->left,depth+1,result);
        Order(cur->right,depth+1,result);
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        if(root==nullptr){
            return result;
        }
        int depth=0;//初始深度为0
        Order(root,depth,result);
        return result;
    }
};

从以上四种递归遍历方式中我们可以发现,前中后序为一组,层序单独为一组。

3.非递归

对于非递归的遍历方式我们需要一些数据结构辅助我们来进行遍历。前中后序遍历通常采用一个栈来辅助遍历,层序遍历需要使用一个辅助队列进行遍历。

3.1前序遍历

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> sta;//辅助栈
        vector<int> result;
        if(root==nullptr){
            return result;
        }
        sta.push(root);
        while(!sta.empty()){
            TreeNode* node;
            node=sta.top();
            result.push_back(node->val);
            sta.pop();
            if(node->right){//由于栈满足先进后出的特性,因此右节点先入栈。
                sta.push(node->right);
            }
            if(node->left){
                sta.push(node->left);
            }
        }
        return result;
    }
};

3.2中序遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> sta;//辅助栈
        vector<int> result;
        if(root==nullptr){
            return result;
        }
        TreeNode* cur;//由于中序遍历的顺序和处理结点的顺序不一致,因此需要一个指针遍历树
        cur=root;
        while(!sta.empty() || cur!=nullptr){
            if(cur!=nullptr ){//根、左先入栈
                sta.push(cur);
                cur=cur->left;
            }else{
                cur=sta.top();
                sta.pop();
                result.push_back(cur->val);//按照左、根的顺序出栈
                cur=cur->right;//处理右结点
            }
        }
        return result;
    }
};

3.3后序遍历

在前序遍历的基础上稍作修改,入栈时左结点先入栈后右结点,因此输出顺序为根右左,最后翻转结果就可以得出后序遍历左右根的顺序。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*>sta;//辅助栈
        vector<int> result;
        if(root==nullptr){
            return result;
        }
        sta.push(root);
        while(!sta.empty()){
            TreeNode* node;
            node=sta.top();
            result.push_back(node->val);
            sta.pop();
            if(node->left){//左结点入栈
                sta.push(node->left);
            }
            if(node->right){//右结点入栈
                sta.push(node->right);
            }
        }
        reverse(result.begin(),result.end());//翻转序列
        return result;
    }
};

3.4层序遍历

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;//辅助队列
        vector<vector<int>> result;
        if(root==nullptr){
            return result;
        }
        que.push(root);
        while(!que.empty()){
            vector<int> temp;
            int size=que.size();//用来遍历当前队列
            for(int i=0;i<size;i++){
                TreeNode* node;
                node=que.front();
                que.pop();
                temp.push_back(node->val);
                if(node->left){
                    que.push(node->left);
                }
                if(node->right){
                    que.push(node->right);
                }
            }
            result.push_back(temp);
        }
        return result;
    }
};

从以上四种非递归遍历方式中我们可以发现,前后序遍历为一组,中序遍历和层序遍历单独为一组。

4.总结

对于二叉树的常见遍历方式不管是递归还是非递归方式我们都应该掌握。最后,我们也可以把二叉树推广到n叉树实现n叉树的前序、后序和层序遍历,不管递归还是非递归思路都是一样的。有同学可能要问为什么没有n叉树的中序遍历,因为对于n叉树而言我们并不知道哪些孩子是左孩子哪些是右孩子,也没这种说法,因此没有中序遍历。

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值