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++语言开发爱好者,本书也有较大的参考价值。
本资源是压缩包形式的, 里面包含 本书,里面是pdf格式的, 带书签目录,本书是完整版的。 资源都是我自己用过的,不骗大家。 本书作者: 肖俊宇 吴为胜; 出版社: 电子工业出版社 内容简介: 《由浅入深学C++:基础、进阶与必做300题(含DVD光盘1张)》是C++语言的入门教程,较为系统地介绍了C++语言的基础内容。本书共分为3篇22章,详细介绍了C++语言的基础知识、面向对象、标准模块、底层开发和综合案例。本书循序渐进地讲述了C++的基础知识、C++程序的组成及其开发过程、C++程序中的数据、表达式和语句、控制程序流程、数组与字符串、指针与引用、使用函数、函数模板、错误和异常处理、宏和预编译、面向对象的开发、封装、继承、多态、类模板、文件流、标准模板库STL和编程实践等内容。 《由浅入深学C++:基础、进阶与必做300题(含DVD光盘1张)》涉及面广,从基本知识到高级内容和核心概念,再到综合案例,几乎涉及C++开发的所有重要知识。本书适合所有想全面学习C++开发技术的人员阅读,尤其适合没有编程基础的C++语言初学者作为入门教程,也可作为大、中院校师生和培训班的教材,对于C++语言开发爱好者,本书也有较大的参考价值。 章节目录: 第1篇 C++基础篇 第1章 C++概述 1 1.1 引言 1 1.1.1 C++的历史沿革 1 1.1.2 入门C++ 2 1.1.3 编程思想的转变 3 1.2 C++概述 4 1.2.1 C++的特征 5 1.2.2 C与C++的比较 5 1.2.3 C++的应用领域 6 1.3 C++源程序的组成 6 1.3.1 基本组成元素 7 1.3.2 标识符 8 1.3.3 保留字 8 1.3.4 符号 8 1.4 C++集成开发环境——DEV-C++ 9 1.4.1 选择C++编译器 9 1.4.2 安装DEV-C++ 10 1.4.3 DEV-C++ IDE简介 11 1.5 第一个C++程序——Hello World 11 1.5.1 创建源程序 11 1.5.2 编译运行 13 1.6 小结 14 1.7 习题 14 第2章 变量与数据类型 18 2.1 常量和变量 18 2.1.1 常量 18 2.1.2 变量 21 2.1.3 变量的定义及赋值 22 2.1.4 变量的应用示例 24 2.2 基本数据类型 25 2.2.1 基本数据类型概述 25 2.2.2 整型数据类型 26 2.2.3 浮点型数据类型 27 2.2.4 字符型数据类型 29 2.2.5 布尔型数据类型 30 2.3 变量的作用域 31 2.4 类型转换 32 2.4.1 隐式转换 32 2.4.2 显式转换 33 2.5 小结 34 2.6 习题 34 第3章 表达式与语句 39 3.1 运算符 39 3.1.1 运算符概述 39 3.1.2 算术运算符 40 3.1.3 自增和自减运算符 42 3.1.4 赋值运算符 43 3.1.5 关系运算符 44 3.1.6 逻辑运算符 45 3.1.7 条件运算符 46 3.1.8 逗号运算符 47 3.1.9 位运算符 48 3.1.10 sizeof运算符 49 3.2 运算符的优先级和结合性 50 3.3 表达式 51 3.4 语句 53 3.4.1 空格的作用 53 3.4.2 语句块 54 3.4.3 赋值语句 55 3.4.4 空语句 56 3.5 小结 57 3.6 习题 57 第4章 流程控制结构之顺序结构 63 4.1 程序流程图 63 4.2 表达式语句 64 4.3 格式化输入/输出 65 4.3.1 标准输入流cin 65 4.3.2 标准输出流cout 66 4.3.3 输出流cerr和clog 68 4.4 格式控制函数 69 4.5 格式控制符 71 4.5.1 控制不同进制的输出 72 4.5.2 控制输出宽度 72 4.5.3 控制输出精度 73 4.6 顺序结构综合应用 74 4.7 小结 75 4.8 习题 75

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逃跑的机械工

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

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

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

打赏作者

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

抵扣说明:

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

余额充值