最近在复习数据结构,在力扣上面找了一个题目做。基础不太好,所以给自己记录一下从懵逼到搞懂的整个过程
测试通过如图
贴一下通过代码
TreeNode* BuildTree(vector<int>& preorder, vector<int>& inorder, int& rooti, int left, int right)
{
if (left > right)
return NULL;
int i = 0;
while (preorder[rooti] != inorder[i])
i++;
TreeNode* root = new TreeNode(preorder[rooti++]);
root->left = BuildTree(preorder, inorder, rooti, left, i - 1);
root->right = BuildTree(preorder, inorder, rooti, i + 1, right);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int rooti=0;
int left=0;
int right=preorder.size()-1;
return BuildTree(preorder,inorder,rooti,left,right);
}
以下是整个题目的思考过程
我的思路
前序进栈,每次递归出栈且第一个为根节点为上一个节点的子节点
然后在中序中找到出栈的元素,一分为二,左边为该根节点左边的子节点,右边为右边的子节点。
然后递归,前序遍历序列出栈,为根节点,重复直到为空。
伪代码如下:
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
typedef struct tree
{
int data;
tree* lchild;
tree* rchild;
};
tree* buildtree(数组1,数组2)
{
queue<int> a;
for (i = 0; i < n; i++)
{
//入队列
a.push(a1[i]);
}
//先序出队
a.出队
为上一个节点的子节点
//中序定位
//分中序组为左右
//前序遍历序列出来的那个数在中序分好的小组中,若左边无则左指针指空,右边无则右指针指空
//怎么链接呢???
return root;
}
int main()
{
int i, n;
cin >> n;
int a[100];
for (i == 0; i < n; i++)
{
cin >> a[i];
}
}
整个懵逼。
问题汇总如下:
1怎么通过指针去形成链接的关系?
通过TreeNode* root创造一个指针root,然后将其赋值为new TreeNode(preorder[rooti++]),这样这一次递归之中的root指向本次新创立的根节点,然后再将本次创立的根节点结构体中的left与right指向新的递归产生的指针,则根节点与自己的两个子节点能够成功地链接在一起。
2怎么将数组输入到函数中?
通过动态存储vector,需要用到头文件#include<vector>;以及vector<int>& 名称;来实现动态输入。
3函数怎么定义类型,tree*吗?
没错,这样能够返回指向tree型的指针。
4队列的头怎么出,然后怎么选这个元素?
不需要使用队列,数组循环即可。
5中序序列以什么方式进行存储,字符串吗?
动态数组存储即可。
6怎么去把它分为多个方便后续使用,怎么去找这个字符串?
不需要分为多个,记录下前序序列中每次产生的新的根节点的位置,通过循环来在中序序列中找到,并通过记录边界来达到每次都能够分为左右数组的目的。
参考代码
TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder, int& rooti, int left, int right)
//问,rooti是啥。
//问,为什么代码的结构为TreeNode*。
//问,vector<int>&中的&有什么用。
//答,rooti 是一个整型引用(int&),用于追踪在前序遍历数组中的根节点的索引。
//答,在 C++ 中,函数的返回类型决定了该函数调用后返回的值的类型。具体到你的//问题中,TreeNode* 是一个指针类型,表示该函数返回一个指向 TreeNode 类型的//指针。
//答,vector<int>& preorder
&这个符号表示引用(reference)。
使用引用传递参数时,不会复制对象,而是直接操作原始对象。这样可以提高性能,尤其是对于大型对象(如 vector)时,避免不必要的拷贝开销。
{
//中序区间不存在
if (left > right) return nullptr;
//问,left跟right是什么,为什么比大小可以判断
//答,left跟right表示中序数列的边界,例如1,2,3,left为0,right为2
int i = 0;
//在中序区间找当前根,划分左右子树
while (preorder[rooti] != inorder[i]) i++;
TreeNode* root = new TreeNode(preorder[rooti++]);
//问,new是干什么
//答,new 操作符会创建一个新的指针,用于动态分配内存。这里创建了一
//个 TreeNode 对象,并返回其指针这样就不需要之前就确定节点的个数。
//问,这句话的语法知识点有哪些,以及有哪些含义。
//答,创建一个指向TreeNode型的指针root,动态分配内存创建一个新的、//TreeNode型的对象,为新产生的节点,赋值为前序遍历序列的下一个值。
//然后root指针等于这个新产生的指针。
//问,这个rooti怎么变化。
//答,先访问preorder[rooti],然后rooti自增。
//递归构建左右子树
// [left, i - 1] i [i + 1 right]
//通过对root->进行操作来给left与right进行赋值与定义
//产生的新结构体TreeNode中的left指向
//i-1表示上一个选中的根的左边为左子树区域,进入递归
root->left = _buildTree(preorder, inorder, rooti, left, i - 1);
//i+1表示上一个选中的根的右边为右子树区域,进入递归
root->right = _buildTree(preorder, inorder, rooti, i + 1, right);
//最终返回根节点的地址
return root;
}
//问,这个函数的作用,不是已经建好树了吗。
//答,用来调用上面的函数。
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
int i = 0;//当前树的根的位置
return _buildTree(preorder, inorder, i, 0, inorder.size() - 1);
}
最后在参考的基础上稍微改了一下,其余基本一致。