C++进阶--二叉树编程题

文章介绍了多个关于二叉树的编程问题,包括根据二叉树创建字符串、二叉树的层序遍历、最近公共祖先的查找、二叉搜索树与双向链表的转换,以及不同遍历方式(前序、中序、后序)的非递归实现。这些内容涉及二叉树的基本操作和算法应用。
摘要由CSDN通过智能技术生成

力扣606. 根据二叉树创建字符串

题目链接:力扣606

在这里插入图片描述

class Solution {
public:
    void _tree2str(TreeNode* root, string& str)
    {
         str += to_string(root->val);

         if(root->left)
         {
             str += '(';
             _tree2str(root->left, str);
             str += ')';
         }
         
         if(root->left == nullptr && root->right)
         {
                str += "(";
                str += ")";
         }

         if(root->right)
         {
             str += '(';
             _tree2str(root->right, str);
             str += ')';
         }
    }

    string tree2str(TreeNode* root) 
    {
         string str;
        _tree2str(root, str);

        return str;
    }
};

力扣102. 二叉树的层序遍历

力扣102
本质就是是一个广度优先搜索, — > 借助队列来完成。
在这里插入图片描述

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
          if(root == nullptr)
               return vector<vector<int>>();

          queue<TreeNode*> q;
          q.push(root);

          vector<vector<int>> vv;
          while(!q.empty())
          {
              int sz = q.size();
              vector<int> v;
              while(sz--)
              {
                  TreeNode* node = q.front();
                  q.pop();

                  v.push_back(node->val);

                  if(node->left)
                        q.push(node->left);
                  if(node->right)
                        q.push(node->right);
              }
            vv.push_back(v);
          }

          return vv;
    }
};

力扣236. 二叉树的最近公共祖先

力扣236

在这里插入图片描述
解题思路 : 我们用一个函数 bool inTree(BTreeNode* root, BTreeNode* x) 去判断这个目标节点p, q是在root的那一侧,
如果都是在左侧, 则到root的左侧去找, 如果都在右侧, 那就到root的右侧去找。
另外的话, p 或者q是root的话, 直接返回root就行

class Solution {
public:
    bool inTree(TreeNode* root, TreeNode* x)
    {
        if (root == nullptr)
            return false;

        if (root->val == x->val)
            return true;

        return inTree(root->left, x) || inTree(root->right, x);
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
    {
        if (root == p || root == q)
            return root;

        bool pLeft = inTree(root->left, p), pRight = !pLeft;
        bool qLeft = inTree(root->left, q), qRight = !qLeft;

        if (pLeft && qLeft)
        {
            return lowestCommonAncestor(root->left, p, q);
        }
        else if (pRight && qRight)
        {
            return lowestCommonAncestor(root->right, p, q);
        }
        else
        {
            return root;
        }

        return nullptr;
    }
};

JZ36 二叉搜索树与双向链表

题目链接: 牛客JZ36

在这里插入图片描述

class Solution {
public:
    void _Convert(TreeNode* root, TreeNode*& pre)       //注意一下, 要传引用!!!!!
	{
        if(root == nullptr)
		         return;
		
		_Convert(root->left, pre);

        root->left = pre;

		if(pre)
		      pre->right = root;

		pre = root;
		_Convert(root->right, pre);
	}

    TreeNode* Convert(TreeNode* pRootOfTree) 
	{
		if(pRootOfTree == nullptr)
		      return nullptr;
			  
         TreeNode* pre = nullptr;
         _Convert(pRootOfTree, pre);

		 TreeNode* head = pRootOfTree;       //这个根节点肯定是在中间的, 通过向前找即可。
		 while(head->left) 
		       head = head->left;

		return head;
    }
};

力扣105–通过前序和中序遍历构造二叉树

力扣105
核心思路 : 通过前序遍历找到根节点, pi是前序遍历的下标,
然后通过中序遍历确定左右子树的范围
根的下标rooti 左树的区间范围 [inbegin rooti-1] 右树的区间范围 : [rooti+1, inend]。

在这里插入图片描述

class Solution {
public:
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder, int& pi, int  inbegin, int inend)
    {
         if(inend < inbegin)  //区间不存在的情况
         {
             return nullptr;        
         }

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

         int rooti = inbegin;    //找出根节点, 分出左,右子树。
         while(rooti <= inend)
         {
             if(root->val != inorder[rooti])
                  rooti++;
             else
                break;
         }
         
         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 pi = 0; // 前序遍历的下标
        
        return _buildTree(preorder, inorder, pi, 0, inorder.size() - 1);

    }
};

力扣144–二叉树的前序遍历(非递归)

力扣144

在这里插入图片描述

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

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

              
              TreeNode* top = st.top();
              st.pop();
              
              cur= top->right;
         }
         
         return v;
    }
};

力扣94–二叉树的中序遍历(非递归)

力扣94
在这里插入图片描述

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

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

             TreeNode* top = st.top();
             st.pop();
             v.push_back(top->val);

             cur = top->right;
        }
        
        return v;
    }
};

力扣145–二叉树的后序遍历(非递归)

力扣145

和前序遍历基本上一样。
前序遍历是 : 根, 左, 右
后序遍历是 : 左,右, 根

核心 : 将后序看出 根, 右, 左 – >最后的结果逆置即可。
我们只用先将右路节点入栈并且访问, 然后出栈的时候将左树节点的右路节点入栈。
然后循环, 最后逆置数组即可。

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

        while(cur || !st.empty())
        {
             while(cur)
             {
                 st.push(cur);
                 v.push_back(cur->val);
                 cur = cur->right;
             }

             TreeNode* top = st.top();
             st.pop();
             cur = top->left;
        }
        
        reverse(v.begin(), v.end());
        return v;
    }
};
本资源是压缩包形式的, 里面包含 本书,里面是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、付费专栏及课程。

余额充值