c++逆天改命进阶--二叉树练习题

1.根据二叉树创建字符串

606. 根据二叉树创建字符串 - 力扣(LeetCode)

image-20220518162512882

class Solution {
public:
    void _tree2str(TreeNode* root, string& str)
    {
        if(root==nullptr)//为空直接返回
        {
            return;
        }
        if(root->left&& root->right)//左右子树均不为空 
        {
            str += to_string(root->val);
            str += "(";
            _tree2str(root->left, str);
            str += ")";
            str += "(";
            _tree2str(root->right, str);
            str += ")";
        }
        else if(root->left == nullptr)
        {
            if(root->right)//左子树为空,右子树不空
            {
                str += to_string(root->val);
                str += "()";
                str += "(";
                _tree2str(root->right, str);
                str += ")";
            }
            else//左右子树都空
            {
                str += to_string(root->val);
            }

        }
        else//左子树不为空,右子树为空
        {
            str += to_string(root->val);
            str += "(";
            _tree2str(root->left, str);
            str += ")";
        }



    }
    string tree2str(TreeNode* root) 
    {
        string s;
        _tree2str(root, s);//调用子函数
        return s;
    }
};

image-20220518171034186

2.二叉树的层序遍历

102. 二叉树的层序遍历 - 力扣(LeetCode)

image-20220518171144775

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        queue<TreeNode*> q;
        if(root == nullptr)//空树直接返回
        {
            return vv;
        }
        q.push(root);//不为空 队列q用来存放每一层的节点指针
        int levelSize = 1;//每层的节点个数,最开始肯定是1
        while(!q.empty())//队列不为空就继续
        {
            vector<int> v;
            while(levelSize--)//节点个数是几,v就插入几次
            {
                TreeNode* front = q.front();//先把第一个节点指针保存下来,然后将该节点从队列删除
                v.push_back(front->val);
                q.pop();
                //接下来判断刚刚删除的节点的左右孩子是否为空,不为空就插入到队列
                if(front->left)
                {
                    q.push(front->left);
                }
                if(front->right)
                {
                    q.push(front->right);
                }
            }
            levelSize = q.size();//更新下一层要插入的次数
            vv.push_back(v);
        }
        return vv;
    }
};

image-20220518181546023

3.二叉树的层序遍历(自底向上)

107. 二叉树的层序遍历 II - 力扣(LeetCode)

image-20220518181652802

该题和上题类似,只需要逆置一下vv里面的vector v,我们直接上代码

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> vv;
        queue<TreeNode*> q;
        if(root == nullptr)
        {
            return vv;
        }
        q.push(root);
        int levelSize = 1;
        while(!q.empty())
        {
            vector<int> v;
            while(levelSize--)
            {
                TreeNode* front = q.front();
                v.push_back(front->val);
                q.pop();
                if(front->left)
                {
                    q.push(front->left);
                }
                if(front->right)
                {
                    q.push(front->right);
                }
            }
            levelSize = q.size();
            vv.push_back(v);
        }
        reverse(vv.begin(), vv.end());
        return vv;

    }
};

image-202205181819521114.二叉树的最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

image-20220518182112337

class Solution {
public:
    bool FindNode(TreeNode* root, TreeNode* x, stack<TreeNode*>& st)
    {
        if(root == nullptr)//root为空返回false
        {
            return false;
        }
        st.push(root);//不为空先把当前节点插入栈中,或许这个节点是目标节点的一个祖先,也有可能不是,那就需要我们在后面再将其pop掉
        if(root == x)//找到了返回true
        {
            return true;
        }
        if(FindNode(root->left, x, st))//在左子树找到了返回true
        {
            return true;
        }
        if(FindNode(root->right, x, st))//在右子树找到了返回true
        {
            return true;
        }
        //到这里,说明我们插入的root不是目标节点的祖先,将其pop掉
        st.pop();
        return false;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack<TreeNode*> st1, st2;//定义两个栈用于保存查找目标节点过程中所有祖先节点
        //查找目标节点
        FindNode(root, p, st1);  
        FindNode(root, q, st2);
        //此时st1里面都是p的祖先,st2里面都是q的祖先。
        //我们假定st1.size()更大,如果不是这样在将其长短交换
        stack<TreeNode*> longSt = st1;
        stack<TreeNode*> shortSt = st2;
        if(longSt.size()<shortSt.size())
        {
            swap(longSt, shortSt);
        }
        //先让长的栈走差距步
        while(longSt.size()>shortSt.size())
        {
            longSt.pop();
        }
        //此时两个栈一样长,从顶部开始依次比较,直到第一次相等,此时找到了最近的公共祖先
        while(longSt.top() != shortSt.top())
        {
            longSt.pop();
            shortSt.pop();
        }
        return longSt.top();
    }
};

image-20220518213800148

5.二插搜索树与双向链表

二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com)

image-20220518214247620

class Solution {//该题显然是用到了中序遍历
public:
    void InOrder(TreeNode* root, TreeNode*& prev)
    {
        if(root==nullptr)//root为空直接返回
        {
            return;
        }
        InOrder(root->left, prev);//不为空先对左子树遍历
        root->left = prev;//左子树遍历之后,将prev赋给left
        if(prev)//如果prev不为空,说明他是上一次的root,上面的那行代码只解决了前驱指针,而在这里我们解决了上一次的root的后继指针的问题。
        {
            prev->right = root;
        }
        
        prev = root;//更新prev
        InOrder(root->right, prev);//中序遍历右子树
    }
    TreeNode* Convert(TreeNode* pRootOfTree) {
        if(pRootOfTree == nullptr)
        {
            return nullptr;
        }
        TreeNode* prev = nullptr;//前驱指针 初识为空,也就是图上4的left为空
        InOrder(pRootOfTree, prev);//中序遍历
        TreeNode* head = pRootOfTree;//找头,找到最左面的节点
        while(head->left)
        {
            head = head->left;
        }
        return head;
        
    }

6.从前序与中序遍历序列构造二叉树

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

image-20220519084958566

class Solution {
public:
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder, int& pi, int inbegin, int inend)
    {
        if(inbegin>inend)//说明该树为空直接return
        {
            return nullptr;
        }
        TreeNode* root = new TreeNode(preorder[pi]);//不为空建树 ,通过前序建树,通过中序找区间
        pi++;
        int rooti = inbegin;
        while(rooti<=inend)
        {
            if(root->val == inorder[rooti])//在中序找到值与root->val相等的下标
            {
                break;
            }
            else
            {
                rooti++;
            }
        }
        //[inbegin, rooti-1][rooti][rooti+1, inend]
        root->left = _buildTree(preorder, inorder, pi, inbegin, rooti-1);
        root->right = _buildTree(preorder, inorder, pi, rooti+1, inend);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int i = 0;
        return _buildTree(preorder, inorder, i, 0, inorder.size()-1);
    }
};
//注意pi必须用& 保证全局只有一个pi  否则会出错

7.从中序与后序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

image-20220519095816910

该题与上题类似,思路大体相同,不同之处在于这道题需要后序来确定根,因为后序是左右根, 所以我们从后序的最后一个值开始建树,并且建好根之后先建右子树,再建左子树。

class Solution {
public:
    TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder, int& pi, int inBegin, int inEnd)
    {
        if(inBegin > inEnd)
        {
            return nullptr;
        }
        TreeNode* root = new TreeNode(postorder[pi]);
        pi--;
        int rooti = inBegin;
        while(rooti <= inEnd)
        {
            if(root->val == inorder[rooti])
            {
                break;
            }
            else
            {
                rooti++;
            }
        }
        //[inBegin,rooti-1][rooti][rooti+1, inEnd]
        
        root->right = _buildTree(inorder, postorder, pi, rooti+1, inEnd);
        root->left = _buildTree(inorder, postorder, pi, inBegin, rooti-1);
        return root;

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

    }
};

8.二叉树的前序遍历(非递归)

144. 二叉树的前序遍历 - 力扣(LeetCode)

image-20220519111214537

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
       TreeNode* cur = root;
       stack<TreeNode*> st;
       vector<int> ret;
       while(cur || !st.empty())//循环条件可以先空着我们之后在分析
       {
           while(cur)//先访问左路节点,并将左路节点入栈
           {
               ret.push_back(cur->val);
               st.push(cur);
               cur = cur->left;
           }
           TreeNode* top = st.top();//top取栈顶元素,然后删除栈顶
           st.pop();
           cur = top->right;//此时左路节点已经访问晚了, 去访问他的右子树。cur指向谁,就表示开始前序遍历哪个树
           //现在我们可以控制循环的条件 :1.cur不为空,说明此时cur指的树的左路节点没有访问完
           //                          2.st不为空,说明左路节点的右子树还没有访问完
       }
       return ret;
    }
};

9.二叉树的中序遍历(非递归)

94. 二叉树的中序遍历 - 力扣(LeetCode)

//该题和上题类似我们直接上代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> ret;
        TreeNode* cur = root;
        while(cur || !st.empty())
        {
            while(cur)//cur不为空左路节点入栈
            {
                st.push(cur);
                cur = cur->left;
            }
            TreeNode* top = st.top();//取出栈顶,并pop掉
            st.pop();
            ret.push_back(top->val);
            cur = top->right;//cur指向top节点的右子树
        }
        return ret;
    }
};

10.二叉树的后序遍历(非递归)

145. 二叉树的后序遍历 - 力扣(LeetCode)

//该题也和前面两题类似
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        TreeNode* prev = nullptr;//用来记录上一次插入的节点
        while(cur || !st.empty())
        {
            while(cur)//左路节点入栈
            {
                st.push(cur);
                cur = cur->left;
            }
            TreeNode* top = st.top();//去栈顶元素
            if(top->right == nullptr || top->right == prev)//如果top->right为空或者top->right为上一次插入的节点,就说明可以插入当前值
            {
                st.pop();
                ret.push_back(top->val);
                prev = top;
            }
            else//否则,访问右子树
            {
                cur = top->right;
            }
        }
        return ret;
    }
};

l

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
由浅入深学C++基础进阶与必做300题 源程序 解压后122M C++是近年广泛使用的程序设计语言,由C语言的基础上发展而来,实现 了由面向过程到面向对象的转变,全面支持面向对象的程序设计方法。C++ 语言在软件工业领域一直处于领先地位,并且自身在不断完善,必将作为高 性能软件开发的基础,在软件开发中发挥主要的作用。 由肖俊宇等编著的《由浅入深学C++--基础进阶与必做300题(附光盘) 》是C++语言的入门教程,较为系统地介绍了C++语言的基础内容。本书共分 为3篇22章,详细介绍了C++语言的基础知识、面向对象、标准模块、底层开 发和综合案例。本书循序渐进地讲述了C++的基础知识、C++程序的组成及其 开发过程、C++程序中的数据、表达式和语句、控制程序流程、数组与字符 串、指针与引用、使用函数、函数模板、错误和异常处理、宏和预编译、面 向对象的开发、封装、继承、多态、类模板、文件流、标准模板库STL和编 程实践等内容。 《由浅入深学C++--基础进阶与必做300题(附光盘)》涉及面广,从基 本知识到高级内容和核心概念,再到综合案例,几乎涉及C++开发的所有重 要知识。本书适台所有想全面学习C++开发技术的人员阅读,尤其适合没有 编程基础的C++语言初学者作为入门教程,也可作为大、中院校师生和培训 班的教材,对于C++语言开发爱好者,本书也有较大的参考价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逃跑的机械工

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值