二叉树的前中后序遍历

       本文源码示例是自己在LeetCode上做的相关题目而来。

前序遍历

       遍历思想:根节点→左子树→右子树

递归版本

/**
 * Definition for a binary tree node.
 * struct TreeNode
 * {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution
{
public:
    void preOrder(vector<int> &vec, TreeNode* root)
    {
        if (root != nullptr)
        {
            vec.push_back(root->val);
            preOrder(vec, root->left);
            preOrder(vec, root->right);
        }
    }
    vector<int> preorderTraversal(TreeNode* root)
    {
        vector<int> ans;
        preOrder(ans, root);
        return ans;
    }
};

非递归版本

       非递归版本需要用栈来模拟递归版本中对节点指针的“保存”以达到回溯目的,因为先序遍历是先访问根节点,所以对每一个节点都可以直接打印,然后将其压入栈中,再将节点指针移动到左子节点中。当节点为空时,将栈顶元素弹出(即获得其父结点的指针),然后将节点指针移动到父结点的右子结点中。

class Solution
{
public:
    vector<int> preorderTraversal(TreeNode* root)
    {
        vector<int> ans;
        if (root == nullptr)
        {
            return ans;
        }
        stack<TreeNode*> nodes;
        TreeNode* pNode = root;
        while (pNode != nullptr || !nodes.empty())
        {
            if (pNode != nullptr)
            {
                ans.push_back(pNode->val);
                nodes.push(pNode);
                pNode = pNode->left;
            }
            else
            {
                pNode = nodes.top()->right;
                nodes.pop();
            }
        }
        return ans;
    }
};

中序遍历

       遍历思想:左子树→根节点→右子树

递归版本

/**
 * Definition for a binary tree node.
 * struct TreeNode
 * {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution
{
public:
    void inOrder(vector<int> &vec, TreeNode* root)
    {
        if (root != nullptr)
        {
            inOrder(vec, root->left);
            vec.push_back(root->val);
            inOrder(vec, root->right);
        }
    }
    vector<int> inorderTraversal(TreeNode* root)
    {
        vector<int> ans;
        inOrder(ans, root);
        return ans;
    }
};

 非递归版本

       中序遍历的非递归版本与前序遍历相似,由于是先打印左子树再打印根节点,所以只需要将打印操作移到出栈后即可。

class Solution
{
public:
    vector<int> inorderTraversal(TreeNode* root)
    {
        vector<int> ans;
        if (root == nullptr)
        {
            return ans;
        }
        stack<TreeNode*> nodes;
        TreeNode* pNode = root;
        while (pNode != nullptr || !nodes.empty())
        {
            if (pNode != nullptr)
            {
                nodes.push(pNode);
                pNode = pNode->left;
            }
            else
            {
                ans.push_back(nodes.top()->val);
                pNode = nodes.top()->right;
                nodes.pop();
            }
        }
        return ans;
    }
};

后序遍历

       遍历思想:左子树→右子树→根节点

递归版本

/**
 * Definition for a binary tree node.
 * struct TreeNode
 * {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution
{
public:
    void postOrder(vector<int> &vec, TreeNode* root)
    {
        if (root != nullptr)
        {
            postOrder(vec, root->left);
            postOrder(vec, root->right);
            vec.push_back(root->val);
        }
    }
    vector<int> postorderTraversal(TreeNode* root)
    {
        vector<int> ans;
        postOrder(ans, root);
        return ans;
    }
};

非递归版本

       后序遍历的非递归版本比前序遍历和中序遍历要难,因为必须保证根节点的左子树和右子树都已经被打印过了才能打印根节点。

       一种思路如下:一个节点可以被打印的条件要么是其左子树和右子树都为空,要么是左子树和右子树都已经打印过了。对于后者,我们需要两个节点指针来帮助我们做出判断:一个节点指针所指向的节点是另一个节点指针的指向节点的父结点。如果不满足被打印的条件,则将该节点的右子结点和左子结点先后压入栈中(注意顺序不能搞错)。

class Solution
{
public:
    vector<int> postorderTraversal(TreeNode* root)
    {
        vector<int> ans;
        if (root == nullptr)
        {
            return ans;
        }
        stack<TreeNode*> nodes;
        TreeNode *parent = nullptr, *child = nullptr;
        nodes.push(root);
        while (!nodes.empty())
        {
            parent = nodes.top();
            if ((parent->left == nullptr && parent->right == nullptr) || (child != nullptr && (child == parent->left || child == parent->right)))
            {
                ans.push_back(parent->val);
                nodes.pop();
                child = parent;
            }
            else
            {
                if (parent->right != nullptr)
                {
                    nodes.push(parent->right);
                }
                if (parent->left != nullptr)
                {
                    nodes.push(parent->left);
                }
            }
        }
        return ans;
    }
};

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值