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

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

递归遍历二叉树:

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

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

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

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

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

二叉树的节点定义如下:

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<val<left);
        preOrderTraversalRecursion(x->right);
    }

中序遍历:

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

后序遍历:

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

总结一下:

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

非递归遍历二叉树:

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

先序遍历:

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

void preOrderTraversalIteration(Node* x){//先序遍历二叉树迭代法:
        if(x == nullptr ) return;
        cout<<"preOrderTraversalIteration"< s;//用栈模拟递归
        s.push(x);//先把头节点压栈
        while (!s.empty()){ //栈非空就继续循环
            Node* cur = s.top(); //栈中弹出节点
            s.pop();
            cout<val<right){
                s.push(cur->right);
            }
            if(cur->left){
                s.push(cur->left);
            }
        }
    }

后序遍历:

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

void postOrderTraversalIteration(Node* x){
        if(x == nullptr) return;
        cout<<"postOrderTraversalIteration"< 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<val<

中序遍历:

void inOrderTraversalIteration(Node* x){//二叉树中序遍历迭代法实现
        if(x == nullptr) return;
        cout<<"inOrderTraversalIteration"< 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<val<right;
            }
        }
    }

层次遍历二叉树:

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

 vector > levelOrder(Node* root) {
        // write code here
        vector > v;
        if(root == nullptr) return v;
        Node* cur = root;
        queue q;
        q.push(cur);
        while(!q.empty()){
            int size = q.size(); //先获取当前层的节点数
            vector ans;
            for(int i = 0;ival);
                if(cur->left){
                    q.push(cur->left);
                }
                if(cur->right){
                    q.push(cur->right);
                }
            }
            v.push_back(ans); 
//二叉树层次遍历正序收集节点;如果要倒序收集,那么每次在首部位置插入即可
        }
        return v;
    }

你可能感兴趣的:(算法,算法,数据结构,蓝桥杯,java,leetcode)