频道栏目
首页 > 资讯 > C++ > 正文

[LeetCode] Binary Tree Preorder Traversal & Binary Tree Postorder Traversal

13-12-13        来源:[db:作者]  
收藏   我要投稿

Given a binary tree, return the preorder traversal of its nodes' values.

Given a binary tree, return the postorder traversal of its nodes' values.

问题描述:给定一个二叉树,返回它的先序和后序遍历序列。

这里给的是先序和后序,中序遍历可以参考Binary Tree Inorder Traversal。

先来看先序,先序和中序类似,只是访问的顺序不太一样。

class Solution {
public:
    vector preorderTraversal(TreeNode *root) {
        // IMPORTANT: Please reset any member data you declared, as
        // the same Solution instance will be reused for each test case.
        stack sta;
        TreeNode *pnode = root;
        vector vec;

        while(pnode || !sta.empty()) {
            while(pnode) {
                vec.push_back(pnode->val);
                sta.push(pnode);
                pnode = pnode->left;
            }
            if(!sta.empty()) {
                pnode = sta.top();
                sta.pop();
                pnode = pnode->right;
            }
        }
        return vec;
    }
};
上面就是先序遍历的代码,当pnode不空或者栈不空时则循环,然后在循环中访问当前节点,然后将当前节点压入栈中,接着当前节点设置为左孩子,执行同样的操作,直到当前节点为空。然后查看栈,如果栈不空,就获取栈顶元素并弹出栈顶元素,然后将当前节点设为右孩子。重复上面的操作,代码和中序基本类似,处理vec.push_back()操作放的地方不一样。

再来看看后序,后序相对复杂,主要复杂的地方在于,当获取栈顶节点的时候是否该访问它呢?也就是说,它的右孩子是否已经访问了呢?

因此,在后序遍历时,栈中的元素除了包含节点指针外,还包含一个标志节点是否访问的变量。下面的代码主要是参考二叉树的非递归后序遍历算法。

class Solution {
public:
    vector postorderTraversal(TreeNode *root) {
        // IMPORTANT: Please reset any member data you declared, as
        // the same Solution instance will be reused for each test case.
        stack<> > sta;
        TreeNode *pnode = root;
        vector vec;
        pair ptnode;

        //从根节点开始,往左下方走,一直走到头,将路径上的每个节点入栈
        while(pnode) {
            sta.push(make_pair(pnode, 0)); //压入栈的有两个信息,一是节点指针,二是其右节点是否被访问过
            pnode = pnode->left;
        }

        while(!sta.empty()) { //当栈非空时
            ptnode = sta.top(); //获取栈顶元素

            //若其右孩子已经被访问过,或是该元素没有右孩子,则由后序遍历的定义,此时就可以访问这个节点了
            if(!ptnode.first->right || ptnode.second) {
                ptnode = sta.top();
                sta.pop();
                vec.push_back(ptnode.first->val);
            }
            else { //若其右孩子存在且它的右孩子没有被访问过,就去处理其右孩子
                ptnode.second = 1;
                sta.pop();
                sta.push(ptnode);
                pnode = ptnode.first->right;
                while(pnode) {
                    sta.push(make_pair(pnode, 0));
                    pnode = pnode->left;
                }
            }
        }
        return vec;
    }
};

小结:

先序:在先序遍历的非递归遍历中,是先沿着左孩子一直遍历,边遍历边访问,然后压入栈中,直到节点为空,然后取栈顶元素,此时,由于它的左孩子在它之后入栈,可以断定,它本身和它的左孩子一定已经被访问过了,按照先序遍历的规则,于是将节点设置为右孩子,然后开始下一轮遍历,也就是说,现在可以访问右子树了。

中序:在中序遍历的非递归遍历中,也是先沿着左孩子一直遍历,但是此时并不访问,只是沿着左孩子将节点都压入栈中,直到当前节点为空,然后取栈顶元素,由于它的左孩子在它之后入栈,因此,当前栈顶节点的左孩子必定已经被访问过了,于是访问当前节点,然后将节点设置为右孩子,开始下一轮遍历。

后序:在后序遍历的非递归遍历中,也是先沿着左孩子,一直遍历,但是此时并不访问,而且在向栈中压入节点时,同时还要保存一个标志信息(标志该节点的右孩子是否被访问过)。然后取栈顶节点,因为栈顶节点的左孩子是在它之后入栈的,因此,它的左孩子一定已经被访问过了,根据后序遍历规则,此时,如果右孩子被访问了,则访问栈顶节点,那么,如何知道右孩子是否被访问了呢?就是之前保存在栈中的标志信息的作用了。如果栈顶节点没有右孩子或者它的右孩子已经被访问过了,此时,就应该访问栈顶节点,并将栈顶节点弹出;否则,就应该访问右子树,但是,在访问右子树之前,应该将当前栈顶节点的标志信息设为1(表示它的右子树已经访问了),然后访问右子树。于是,后序的非递归遍历也可以这样:

class Solution {
public:
    vector postorderTraversal(TreeNode *root) {
        // IMPORTANT: Please reset any member data you declared, as
        // the same Solution instance will be reused for each test case.
        stack<> > sta;
        TreeNode *pnode = root;
        vector vec;
        pair ptnode;

        while(pnode || !sta.empty()) {
            while(pnode) {
                sta.push(make_pair(pnode, 0));
                pnode = pnode->left;
            }
            if(!sta.empty()) {
                ptnode = sta.top();

                if(!ptnode.first->right || ptnode.second) {
                    sta.pop();
                    vec.push_back(ptnode.first->val);
                }
                else {
                    ptnode.second = 1;
                    sta.pop();
                    sta.push(ptnode);
                    pnode = ptnode.first->right;
                }
            }
        }
        return vec;
    }
};

相关TAG标签
上一篇:delphi 短信猫(SMS)编程总结
下一篇:Java DES 加密 解密 示例
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站