二叉树遍历问题

个人主页:Lei宝啊 

愿所有美好如期而遇


目录

递归

前序遍历

中序遍历

后序遍历

前序中序还原二叉树

中序后序还原二叉树

非递归

前序遍历

中序遍历

后序遍历

分层遍历


递归

前序遍历

void PrevOrder(BT_Tree* node)
{
	if (node == NULL)
		return;

	printf("%c ", node->data);
	PrevOrder(node->left);
	PrevOrder(node->right);		
}

中序遍历

void InOrder(BT_Tree* node)
{
	if (node == NULL)
		return;
	
	PrevOrder(node->left);
	printf("%d ", node->data);
	PrevOrder(node->right);
}

后序遍历

void LastOrder(BT_Tree* node)
{
	if (node == NULL)
		return;

	PrevOrder(node->left);	
	PrevOrder(node->right);
	printf("%d ", node->data);
}

前序中序还原二叉树

思路是通过前序序列确定根,中序序列划分左右子树

  • 前序遍历:根 左子树 右子树
  • 中序遍历:左子树 根 右子树

前序序列:3  1  9  2  8  5  4  6
中序序列:9  8  2  1  5  3  4  6 

先确定3是根,然后在中序序列中找到3的位置,左子树区间就是{9,8,2,1,5},右子树区间就是{4,6},然后再确认左子树的根,也就是1,再划分区间,他的左子树区间是{9,8,2},右子树区间就是{5},如果我们以下标来说,就是[0,2]和[4,4](1的右边只有5,也就是说右子树的右边界就是5的下标,左边界就是1的下标加1,这里的下标指的都是中序序列中的下标,因为划分左右子树是在中序序列中进行的),我们按照这样的思路,不断划分,创建节点,返回条件是划分的区间的左右边界下标,当左边界下标大于右边界下标时返回空,否则,我们执行我们写的代码后,返回创建的节点,并进行连接。

class Solution 
{
public:
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder, 
                         int& rooti, int begin, int end) {
        if (begin > end)
            return nullptr;

        TreeNode* root = new TreeNode(preorder[rooti++]);

        int temp = begin;
        while (temp <= end)
        {
            if (preorder[rooti - 1] == inorder[temp])
                break;
            else
                temp++;
        }

        root->left = _buildTree(preorder, inorder, rooti, begin, temp - 1);
        root->right = _buildTree(preorder, inorder, rooti, temp + 1, end);

        return root;

    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int i = 0;
        return _buildTree(preorder, inorder, i, 0, preorder.size() - 1);
    }
};

中序后序还原二叉树

这里参照前面的逻辑就很好理解,唯一需要注意的一点是:这里还原时要先从右子树开始还原,因为后序遍历的根是先从右子树出现的。

  • 后序遍历:左子树 右子树 根
  • 中序遍历:左子树 根 右子树

class Solution 
{
public:
    TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder, int& rooti, int begin, int end) {
        if (begin > end)
            return nullptr;

        TreeNode* root = new TreeNode(postorder[rooti--]);

        int temp = begin;
        while (temp <= end)
        {
            if (postorder[rooti + 1] == inorder[temp])
                break;
            else
                temp++;
        }

        root->right = _buildTree(inorder, postorder, rooti, temp + 1, end);
        root->left = _buildTree(inorder, postorder, rooti, begin, temp - 1);

        return root;

    }

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int i = inorder.size() - 1;
        return _buildTree(inorder, postorder, i, 0, inorder.size() - 1);
    }
};

非递归

前序遍历

我们的思路是分成两个过程:

  • 通过栈存储左路节点,并将左路节点的值放入数组
  • 出栈,访问出栈的节点的右树

 如此循环执行,结束条件就是指向temp右树的变量为nullptr并且栈为空。

class Solution 
{
public:
    vector<int> preorderTraversal(TreeNode* root) 
    {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode* cur = root;

        while (cur || !st.empty())
        {

            while (cur)
            {
                st.push(cur);
                v.push_back(cur->val);
                cur = cur->left;
            }

            TreeNode* temp = st.top();
            st.pop();

            cur = temp->right;
        }

        return v;
    }
};

中序遍历

这里只变动了一行代码,从入栈时访问节点变成出栈时访问节点。

class Solution 
{
public:
    vector<int> inorderTraversal(TreeNode* root) 
    {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode* cur = root;

        while (cur || !st.empty())
        {

            while (cur)
            {
                st.push(cur);
                cur = cur->left;
            }

            TreeNode* temp = st.top();
            st.pop();

            //出栈后再进行访问
            v.push_back(temp->val);
            cur = temp->right;
        }

        return v;
    }
};

后序遍历

这里的逻辑就是如果栈顶的节点的右树为空,或者当访问当前节点时他的右孩子是前一个访问的节点,我们出栈并将节点值push_back进v。

class Solution 
{
public:
    vector<int> postorderTraversal(TreeNode* root) 
    {
        vector<int> v;
        stack<TreeNode*> st;

        TreeNode* cur = root;
        TreeNode* prev = nullptr;

        while (cur || !st.empty())
        {

            while (cur)
            {
                st.push(cur);
                cur = cur->left;
            }

            TreeNode* temp = st.top();

            if (temp->right == nullptr || temp->right == prev)
            {
                v.push_back(temp->val);
                st.pop();
            }
            else
            {
                cur = temp->right;
            }

            prev = temp;
        }

        return v;
    }
};

分层遍历

我们将每层的节点分别push_back进他们各自层级的vector<int> v中,然后将所有v push_back进vector<vector<int>> vv中。

这里我们借助队列,首先将3入队列,计算出3这个节点本层有levelsize个节点,我们就循环levelsize次使本层的levelsize个节点分别将他们的左右孩子带入队列,并在循环过程中,将本层的节点的值push_back进vector<int> v中,每循环一次,队列出一个节点。

结束条件为队列为空。

class Solution 
{
public:

    void reform(vector<vector<int>>& vv, queue<TreeNode*>& qt, TreeNode* root)
    {
        qt.push(root);

        while (!qt.empty())
        {
            vector<int> v;
            int levelsize = qt.size();

            for (int i = 0; i < levelsize; i++)
            {
                TreeNode* node = qt.front();
                if (node)
                    v.push_back(node->val);

                if (node && node->left)
                    qt.push(node->left);
                if (node && node->right)
                    qt.push(node->right);

                qt.pop();
            }
            vv.push_back(v);
        }
    }

    vector<vector<int>> levelOrder(TreeNode* root) 
    {

        vector<vector<int>> vv;
        queue<TreeNode*> qt;

        if (root == nullptr)
            return vv;

        reform(vv, qt, root);
        return vv;
    }
};

从最底层层序遍历,只改动一行代码,我们将结果reverse即可,因为我们每个元素是vector<int>,所以可以这么做。 

class Solution 
{
public:
    void reform(vector<vector<int>>& vv, queue<TreeNode*>& qt, TreeNode* root)
    {
        qt.push(root);


        while (!qt.empty())
        {
            vector<int> v;
            int levelsize = qt.size();


            for (int i = 0; i < levelsize; i++)
            {
                TreeNode* node = qt.front();
                if (node)
                    v.push_back(node->val);


                if (node && node->left)
                    qt.push(node->left);
                if (node && node->right)
                    qt.push(node->right);


                qt.pop();
            }
            vv.push_back(v);
        }
    }


    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> vv;
        queue<TreeNode*> qt;


        if (root == nullptr)
            return vv;


        reform(vv, qt, root);
        reverse(vv.begin(), vv.end());
        return vv;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lei宝啊

觉得博主写的有用就鼓励一下吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值