二叉树的前序、中序、后序非递归遍历、层次遍历

一、先序遍历:

1.根节点进栈

2.节点出栈,并访问,若有右孩子,右孩子进栈,若有左孩子,左孩子进栈

3.重复2直至栈空

--------------01

------02-------------09

--03-----06-----10-----13

04-05-07-08-11-12-14-15

/**

 * Definition for binary tree

 * 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) {

        vector<int> result;

        if(!root)return result;

        stack<TreeNode *> s;

        s.push(root);

        while(!s.empty()){

            TreeNode *p = s.top();

            s.pop();

            result.push_back(p->val);

            if(p->right) s.push(p->right);

            if(p->left) s.push(p->left);

        }

        return result;

    }

};

二、中序遍历:

1.节点进栈,若有左孩子则将指针指向左孩子,重复进行,直到最左

2.节点退栈,并访问。若有右孩子,则将指针指向右孩子

3.重复1 2直至栈空且树空

--------------08

------04-------------12

--02-----06-----10-----14

01-03-05-07-09-11-13-15

class Solution {

public:

    vector<int> inorderTraversal(TreeNode *root) {

        vector<int> result;

        if(!root) return result;

        TreeNode *p = root;

        stack<TreeNode *> s;

        while(!s.empty() || p != nullptr){

            if(p != nullptr){//向左一直到最左

                s.push(p);

                p = p->left;

            }else{

                //访问节点,再转向右子树

                p = s.top();

                s.pop();

                result.push_back(p->val);

                //转向右子树

                if(p->right){

                    p = p->right;

                }else{

                    p = nullptr;

                }

            }

        }

        return result;

    }

};

 

三、后序遍历:

1.节点进栈,若有左孩子则将指针指向左孩子,重复进行,直到最左

2.取栈顶节点(不出栈),若无右孩子或右孩子已经访问,则节点出栈并访问,并作访问标记。若有右孩子且右孩子未被访问,则将指针指向右孩子

3.重复1 2直至栈空且树空

--------------15

------07-------------14

--03-----06-----10-----13

01-02-04-05-08-09-11-12

class Solution {

public:

    vector<int> postorderTraversal(TreeNode *root) {

        vector<int> result;

        if(!root) return result;

        TreeNode *p = root;

        //后序遍历需要一个指针来标记前一个访问的节点

        //用于区分是从左子树还是右子树回退到根节点

        TreeNode *pre = nullptr;

        stack<TreeNode *> s;

        while(!s.empty() || p != nullptr){

            if(p != nullptr){//向左一直到最左

                s.push(p);

                p = p->left;

            }else{

                //访问节点之前,先要判断右子树是否访问过

                p = s.top();

                if(p->right && pre != p->right){

                    //右子树未访问,转向右子树

                    p = p->right;

                }else{

                    //右子树不存在或者已经访问过,则访问根节点

                    s.pop();

                    result.push_back(p->val);

                    pre = p;

                    p = nullptr;

                }

            }

        }

        return result;

    }

};

四、层次遍历:

1.根节点入队

2.队首节点出队并访问,若有左孩子,则左孩子入队,若有右孩子,则右孩子入队

3.重复2直至队空

class Solution {

public:

        vector<vector<int> > Print(TreeNode* pRoot) {

            vector<vector<int> >result;

            if(!pRoot)return result;

            queue<TreeNode *> que;

            que.push(pRoot);

            TreeNode *p;

            size_t levSize = que.size();//记录每层的节点数量

            vector<int> levArr;//保存每一层从左至右的数据

            while(!que.empty()){

                p = que.front();

                if(p->left) que.push(p->left);

                if(p->right) que.push(p->right);

                levArr.push_back(p->val);

                que.pop();

                --levSize;

                if(levSize == 0){//一层遍历完

                    result.push_back(levArr);

                    levArr.clear();

                    levSize = que.size();

                }

            }

            return result;

        }

};

 

总结:

中序遍历和后序遍历有着相似的代码结构,在访问节点的时候,左子树都已经访问完了。中序遍历是直接访问节点,再转向右子树。后序遍历是先要判断是右子树是否存在访问过,如果存在且未访问过,须先访问右子树,待右子树访问完毕后再访问根节点。

 

后序遍历非递归是先访问左子树、再右子树、最后根。可以用栈来存储节点,必须分清返回根节点时,是从左子树返回的,还是从右子树返回的,所以,使用辅助指针pre,指向最近访问过的节点。也可以在节点中增加一个标志域,记录是否已经被访问

 

后序遍历非递归法可以用来求根节点到某节点的路径、公共祖先等。

因为访问某个节点p的时候,栈中节点恰好是p节点的所以祖先,从栈底到栈顶再加上p节点,刚好构成根节点到p节点的一条路径。

如求pq公共祖先的思路:后序找到p后q,保存此时的栈中元素。在继续找到另一个,用此时的栈中元素和先前元素中的栈去比对。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值