详细讲解二叉树先序-中序-后序递归和非递归遍历以及层次遍历

本文详细介绍了二叉树的四种遍历方式:先序、中序、后序和层次遍历。通过递归和非递归两种方法实现,递归方法代码简洁但开销较大,非递归方法使用栈或队列模拟。非递归先序遍历通过调整压栈顺序得到后序遍历。层次遍历则利用队列实现宽度优先搜索。
摘要由CSDN通过智能技术生成

二叉树有先序遍历(根左右)、中序遍历(左根右)和后序遍历(左右根)和层次遍历几种遍历方式。这几种遍历方式是其他二叉树解题的基础,所以必须先掌握。

递归遍历二叉树:

        因为二叉树本身就是用递归定义的,因此采用递归的方法实现三种遍历代码简洁且容易理解,但其开销比较大。

二叉树的先序、中序和后序遍历:

先序遍历:任何子树的处理顺序都是:先根结点,再左子树,然后右子树 (根左右)

中序遍历:任何子树的处理顺序都是:先左子树,再根节点,然后右子树 (左根右)

后序遍历:任何子树的处理顺序都是:先左子树,再右子树,然后根结点 (左右根)

二叉树的节点定义如下:

struct  Node{
    int val;
    Node* left;
    Node* right;
    Node() {
        val = 0;
        left = nullptr;
        right = nullptr;
    }
    Node(int v){
        val = v;
        left = nullptr;
        right = nullptr;
    }
};

先序遍历:

  void preOrderTraversalRecursion(Node* x){
        if(x == nullptr) return;
        cout<<x->val<<endl;
        preOrderTraversalRecursion(x->left);
        preOrderTraversalRecursion(x->right);
    }

中序遍历:

void inOrderTraversalRecursion(Node* x){
        if(x == nullptr) return;
        inOrderTraversalRecursion(x->left);
        cout<<x->val<<endl;
        inOrderTraversalRecursion(x->right);
    }

后序遍历:

 void postOrderTraversalRecursion(Node* x){
        if(x == nullptr) return;
        postOrderTraversalRecursion(x->left);
        postOrderTraversalRecursion(x->right);
        cout<<x->val<<endl;
    }

总结一下:

        二叉树的递归遍历实际上是对二叉树的递归序(二叉树每个节点都会遍历三次),在第i次到达的时候打印根节点。(第1次到达就是先序遍历,第2次到达就是中序遍历,第3次到达就是后序遍历)

非递归遍历二叉树:

        非递归遍历二叉树就是用自己实现的栈替代系统栈。注:任何递归函数都可以改成非递归。

先序遍历:

        注意因为栈是先进后出的,所以是先压右子树再压左子树,这样就能保证出栈是左边先出右边后出。

void preOrderTraversalIteration(Node* x){//先序遍历二叉树迭代法:
        if(x == nullptr ) return;
        cout<<"preOrderTraversalIteration"<<endl;
        stack<Node*> s;//用栈模拟递归
        s.push(x);//先把头节点压栈
        while (!s.empty()){ //栈非空就继续循环
            Node* cur = s.top(); //栈中弹出节点
            s.pop();
            cout<<cur->val<<endl;
            //cur有右节点就压入栈,有左节点就压入栈(因为栈是后进先出,所以按照根左右的遍历,应该先压右子树节点)
            if(cur->right){
                s.push(cur->right);
            }
            if(cur->left){
                s.push(cur->left);
            }
        }
    }

后序遍历:

        上面已经实现了非递归先序遍历(根左右),那么只要稍微加工就可以得到非递归后序遍历。将非递归先序遍历的压栈顺序改一下,改成先压左子树再压右子树,那么最终的遍历顺序是<根右左>,然后在每次弹出打印时候改成不打印,进入另外一个temp栈,当整个操作完成后。从temp栈中弹出元素,那么<根右左>就变成了<左右根>,这就是后序遍历。

void postOrderTraversalIteration(Node* x){
        if(x == nullptr) return;
        cout<<"postOrderTraversalIteration"<<endl;
        stack<Node*> s,tmp;//s是类似于辅助先序遍历的栈;tmp是保存遍历元素,最后输出就是后序遍历
        s.push(x);
        while (!s.empty()){
            Node* cur = s.top();
            s.pop();
            tmp.push(cur);
            if(cur->left){
                s.push(cur->left);
            }
            if(cur->right){
                s.push(cur->right);
            }
        }
        while (!tmp.empty()){
            Node* t = tmp.top();
            cout<<t->val<<endl;
            tmp.pop();
        }
    }

中序遍历:

void inOrderTraversalIteration(Node* x){//二叉树中序遍历迭代法实现
        if(x == nullptr) return;
        cout<<"inOrderTraversalIteration"<<endl;
        stack<Node* > s;
        Node* cur = x;
        Node* tmp = nullptr;
        //栈不为空或者cur不为空,那么循环继续
        while (!s.empty() || cur){
            if(cur){ //以cur为头节点的树,整条左边进栈(包括cur这个根节点),直到遇到cur的左边为nullptr结束
                s.push(cur);
                cur = cur->left;
            }else {
                cur = s.top(); //从栈中弹出cur,经过上面if判断cur的左边是nullptr,访问cur后,让cur=cur->right;
                s.pop();
                cout<<cur->val<<endl;
                cur = cur->right;
            }
        }
    }

层次遍历二叉树:

        层次遍历二叉树需要用队列实现,就是宽度优先遍历,每层入队然后出队让左右孩子分别入队。

 vector<vector<int> > levelOrder(Node* root) {
        // write code here
        vector<vector<int> > v;
        if(root == nullptr) return v;
        Node* cur = root;
        queue<Node*> q;
        q.push(cur);
        while(!q.empty()){
            int size = q.size(); //先获取当前层的节点数
            vector<int> ans;
            for(int i = 0;i<size;++i){ //将当前层的节点遍历,同时将它的孩子节点加入队列
                cur = q.front();
                q.pop();
                ans.push_back(cur->val);
                if(cur->left){
                    q.push(cur->left);
                }
                if(cur->right){
                    q.push(cur->right);
                }
            }
            v.push_back(ans); 
//二叉树层次遍历正序收集节点;如果要倒序收集,那么每次在首部位置插入即可
        }
        return v;
    }
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值