数据结构二叉树基础oj练习2(源码+算法思路)
Posted 华数云图科创小分队
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构二叉树基础oj练习2(源码+算法思路)相关的知识,希望对你有一定的参考价值。
1.另一棵树的子树
给你两棵二叉树 root
和 subRoot
。检验 root
中是否包含和 subRoot
具有相同结构和节点值的子树。如果存在,返回 true
;否则,返回 false
。
二叉树 tree
的一棵子树包括 tree
的某个节点和这个节点的所有后代节点。tree
也可以看做它自身的一棵子树。
力扣https://leetcode.cn/problems/subtree-of-another-tree/
/**
* Definition for a binary tree node.
* struct TreeNode
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* ;
*/
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
if(p==NULL&&q==NULL)
return true;
//其中一个为空,
if(p==NULL||q==NULL)
return false;
//都不为空
if(p->val!=q->val)
return false;
return isSameTree(p->left,q->left)
&&isSameTree(p->right,q->right);
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
if(root==NULL)
return false;
if(isSameTree(root,subRoot))
return true;
return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
这道题是下面这个题的进阶版
力扣https://leetcode.cn/problems/same-tree/
这段代码是用来判断一棵树是否是另一棵树的子树。函数 isSameTree() 是用来判断两棵树是否相同,函数 isSubtree() 则是通过不断递归左右子树来判断是否为子树。
具体实现思路如下:
- 如果根节点为空,则肯定不存在子树,返回 false。
- 如果当前根节点与子树的根节点相同,则直接调用 isSameTree() 函数来比较它们是否完全相同,如果相同则说明找到了子树,返回 true。
- 如果当前根节点与子树的根节点不同,那么继续递归查找左右子树,并将两者的结果进行逻辑或运算,若其中一个为 true,说明找到了子树,返回 true,否则返回 false。
函数 isSameTree() 判断两棵树是否相同的实现思路如下:
- 如果两棵树都为空,则认为它们相同,返回 true。
- 如果其中有一棵树为空,另一棵树不为空,则认为它们不相同,返回 false。
- 如果两棵树的根节点值不相同,则认为它们不相同,返回 false。
- 如果两棵树的根节点值相同,则递归地比较它们的左右子树,只有左右子树都相同,才认为这两棵树相同,否则返回 false。
总体上,这个算法的时间复杂度是 O(nm),其中 n 是原树的节点数,m 是子树的节点数。空间复杂度为 O(max(n,m)),即递归深度。这个算法利用了树的递归结构,通过不断地递归查找子树来判断是否存在子树,因此实现相对简单,但是时间复杂度较高。
2.二叉树遍历
描述
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入描述:
输入包括1行字符串,长度不超过100。
输出描述:
可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。
#include <stdio.h>
struct TreeNode
struct TreeNode*left;
struct TreeNode*right;
char val;
;
struct TreeNode*CreateTree(char*a,int* pi)
if(a[*pi]=='#')
(*pi)++;
return NULL;
struct TreeNode*root=(struct TreeNode*)malloc(sizeof(struct TreeNode));
root->val=a[(*pi)++];
root->left=CreateTree(a,pi);
root->right=CreateTree(a,pi);
return root;
void inOrder(struct TreeNode*root)
if(root==NULL)
return;
inOrder(root->left);
printf("%c ",root->val);
inOrder(root->right);
void DestroyTree(struct TreeNode* root)
if(root == NULL)
return;
DestroyTree(root->left);
DestroyTree(root->right);
free(root);
int main()
char a[100];
scanf("%s",a);
int i=0;
struct TreeNode*root=CreateTree(a, &i);
inOrder(root);
DestroyTree(root);
return 0;
这段代码是在 C 语言中使用递归算法实现二叉树的先序遍历和销毁。其中 CreateTree 函数用于根据输入的字符串构建二叉树,每次递归调用 CreateTree 函数时,都从字符数组 a 中读取一个字符,并根据该字符构建根节点,然后递归创建左子树和右子树,直到遇到结束标识符 '#',返回 NULL 结束递归。
inOrder 函数用于进行中序遍历,其思路和 CreateTree 函数类似,也是先递归访问左子树,再访问根节点,最后递归访问右子树。
DestroyTree 函数用于释放二叉树占用的内存空间。它首先递归地销毁左子树和右子树,然后释放根节点所占用的内存空间。这样可以保证在程序结束时,完全释放二叉树所占用的内存空间,避免出现内存泄露的问题。
在 main 函数中,首先读入一个输入字符串,然后调用 CreateTree 函数构建二叉树,使用 inOrder 函数进行中序遍历,最后调用 DestroyTree 函数释放内存空间,结束程序的执行
数据结构之二叉树的基础OJ练习二叉树的遍历
二叉树的前序遍历
题目来源:二叉树的前序遍历
题目描述:
给你二叉树的根节点
root
,返回它节点值的 前序 遍历。示例 1:
输入:root = [1,null,2,3] 输出:[1,2,3]
示例 2:
输入:root = [] 输出:[]
示例 3:
输入:root = [1] 输出:[1]
示例 4:
输入:root = [1,2] 输出:[1,2]
示例 5:
输入:root = [1,null,2] 输出:[1,2]
解题思路:
规则是若二叉树为空,则空操作返回,否则先访问根节点,然后前序遍历左子树,然后再前序遍历右子树。可以利用递归实现
代码如下:
因为题目要求我们返回前序遍历的结果,故我们需要开辟一个数组来保存前序遍历的结果,但是开辟时我们不知道数组的大小,故我们可以再写一个计算二叉树节点个数的函数,这样就明确了开辟的空间,然后我们写一个前序遍历的函数,只不过我们的这个前序遍历访问节点的方式变成了将当前节点的值赋给数组,最后返回该数组即可
int TreeSize(struct TreeNode* root)
{
if(root==NULL)
return 0;
return TreeSize(root->left)+TreeSize(root->right)+1;
}
void _preorderTraversal(struct TreeNode* root,int arr[],int* pi)
{
//每个递归调用栈帧中都有一个i,下一层i++,不会对上一层的i有影响,故要传地址
if(root==NULL)
return ;
arr[(*pi)++]=root->val;
_preorderTraversal(root->left,arr,&i);
_preorderTraversal(root->right,arr,&i);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
*returnSize = TreeSize(root);
int *a = malloc(sizeof(int)*(*returnSize));
int i=0;
_preorderTraversal(root,a,&i);
return arr;
}
二叉树的中序遍历
题目来源:
题目描述:
给定一个二叉树的根节点
root
,返回它的 中序 遍历。示例 1:
输入:root = [1,null,2,3] 输出:[1,3,2]
示例 2:
输入:root = [] 输出:[]
示例 3:
输入:root = [1] 输出:[1]
示例 4:
输入:root = [1,2] 输出:[2,1]
示例 5:
输入:root = [1,null,2] 输出:[1,2]
中序遍历和前序遍历是一样的,代码也直接将访问节点改在了先访问左子树后面,故就不说思路了,直接贴代码:
代码如下:
int TreeSize(struct TreeNode* root)
{
if(root==NULL)
return 0;
return TreeSize(root->left)+TreeSize(root->right)+1;
}
void _preorderTraversal(struct TreeNode* root,int arr[],int* pi)
{
//每个递归调用栈帧中都有一个i,下一层i++,不会对上一层的i有影响,故要传地址
if(root==NULL)
return ;
_preorderTraversal(root->left,arr,&i);
arr[(*pi)++]=root->val;
_preorderTraversal(root->right,arr,&i);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
*returnSize = TreeSize(root);
int *a = malloc(sizeof(int)*(*returnSize));
int i=0;
_preorderTraversal(root,a,&i);
return arr;
}
二叉树的后序遍历
题目来源:
题目描述:
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3] 1 \\ 2 / 3 输出: [3,2,1]
后序遍历和前面两个遍历是一样的,代码也直接将访问节点改在了先访问左子树和右子树后面,故就不说思路了,直接贴代码:
代码如下:
int TreeSize(struct TreeNode* root)
{
if(root==NULL)
return 0;
return TreeSize(root->left)+TreeSize(root->right)+1;
}
void _preorderTraversal(struct TreeNode* root,int arr[],int* pi)
{
//每个递归调用栈帧中都有一个i,下一层i++,不会对上一层的i有影响,故要传地址
if(root==NULL)
return ;
_preorderTraversal(root->left,arr,&i);
_preorderTraversal(root->right,arr,&i);
arr[(*pi)++]=root->val;
}
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
*returnSize = TreeSize(root);
int *a = malloc(sizeof(int)*(*returnSize));
int i=0;
_preorderTraversal(root,a,&i);
return arr;
}
以上是关于数据结构二叉树基础oj练习2(源码+算法思路)的主要内容,如果未能解决你的问题,请参考以下文章