前言:
基于对(C语言)数据结构之二叉树的讲解,我们在这里给小伙伴们讲解了几道二叉树经典oj题练习题,话不多说一起来看看吧!
1.单值二叉树
思路:
通过根我们就看当前的左右子树的值是否和根结点相同,一旦不同返回false,下面的就不再比较了。如果相同的话就再往下递归,直到递归到叶子节点时之前的结点还符合条件,那么就返回true。而且逻辑与(&&)操作符从前向后看,一旦前面有一个false后面的就不执行了。
实现代码:
bool isUnivalTree(struct TreeNode* root){
if(root==NULL)
{
return true;
}
if(root->left)
{
if(root->val!=root->left->val)
return false;
}
if(root->right)
{
if(root->val!=root->right->val)
{
return false;
}
}
return isUnivalTree(root->left)&&isUnivalTree(root->right);
}
2.检查两颗树是否相同
思路:
从结构上来说,如果两个二叉树都为空,则两个二叉树相同。如果两个二叉树中有且只有一个为空,则两个二叉树一定不相同。
从数值上来说,如果两个二叉树都不为空,那么首先判断它们的根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别判断两个二叉树的左子树是否相同以及右子树是否相同。这是一个递归的过程,因此可以使用深度优先搜索也就是说先递归到这两颗树左下的结点然后再依次往回反,递归地判断两个二叉树是否相同。
实现代码:
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
//同时为NULL符合条件
if(p==NULL&&q==NULL)
{
return true;
}
//能走到这里说明,不是同时为NULL,那就是一个为NULL一个不为NULL,结构不同直接返回false
if((p==NULL&&q!=NULL)||(p!=NULL&&q==NULL))
{
return false;
}
//结构相同再看是否值域相同,值域不同返回false
if(p->val!=q->val)
{
return false;
}
return isSameTree(p->left, q->left)&&isSameTree(p->right, q->right);
}
3.对称二叉树
思路:
如果一个树的左子树与右子树镜像对称,那么这个树是对称的。
因此,如果同时满足下面的条件,两个树互为镜像:
1、它们的两个根结点具有相同的值
2、每个树的右子树都与另一个树的左子树镜像对称
我们可以实现这样一个递归函数,通过同步移动两个指针的方法来遍历这棵树,p 指针和 q指针一开始都指向这棵树的根,随后 p 右移时,q左移,p 左移时,q 右移。每次检查当前 p 和 q 节点的值是否相等,如果相等再判断左右子树是否对称。
实现代码:
bool check(struct TreeNode *p, struct TreeNode *q)
{
if(p==NULL&&p==NULL)//同时为NULL
{
return true;
}
if(p==NULL||q==NULL)//有一个为NULL
{
return false;
}
if(p->val!=q->val)//结点的值不相同时也返回false
{
return false;
}
return check(p->left, q->right)&&check(p->right, q->left);
}
bool isSymmetric(struct TreeNode* root){
return check(root, root);
}
4.二叉树的前序遍历
思路:
首先我们需要了解什么是二叉树的前序遍历:按照访问根节点——左子树——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。
下面的代码是要把遍历的结果存到一个array数组中然后返回数组名即可。
实现代码:
int Treesize(struct TreeNode* root)//求元素个数的函数
{
if(root==NULL)
return 0;
return Treesize(root->left)+Treesize(root->right)+1;
}
void MY_preorderTraversal(struct TreeNode* root,int *a,int *n)
{
if(root==NULL)
{
return;
}
a[*n]=root->val;//根结点
(*n)++;
MY_preorderTraversal(root->left,a,n);//左子树
MY_preorderTraversal(root->right,a,n);//右子树
}
int* preorderTraversal(struct TreeNode* root, int* returnSize){
int n=Treesize(root);//确定元素个数
int *array=(int*)realloc(NULL,sizeof(int)*n);//申请n个4字节大小的空间
int num=0;//数组的下标
MY_preorderTraversal(root,array,&num);//&num传址调用
*returnSize = n;//要返回的元素个数
return array;
}
5.另一颗树的子树
思路:
从头开始向下递归,先在root里找和subRoot根结点值相同的结点,找到了就从这个结点开始和subRoot开始比对是否是同一颗树,若相同就向递归的上一层返回true,不相同就再往下递归,直到递归到叶子结点为止此时我们返回false,在isSubtree函数里最后一行用的是逻辑或||。就代表左右子树若有一个地方找到了与subRoot相同的树,那么整体这个函数就是true。
实现代码:
bool isSameTree(struct TreeNode* p, struct TreeNode* q)//利用前面判断两棵树是否相同
{
if(p==NULL&&q==NULL)
{
return true;
}
if((p==NULL&&q!=NULL)||(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;
}
//如果结点值相同并且结构相同返回true
if(root->val==subRoot->val&&isSameTree(root, subRoot))
{
return true;
}
return isSubtree(root->left, subRoot)||isSubtree(root->right, subRoot);
}
6.二叉树的构建+遍历
思路:
我们先自己定义一个二叉树结构体类型,然后基于分治的思想,递归构建二叉树,构建二叉树先malloc出根节点然后再构建左子树,右子树即可。因为字符串需要构建之后指针向后移动找到下一个字符,所以需要定义一个i下标,通过传址调用把i的地址传过去,实现对下标i的控制。构建之后i下标向后移动,指针指向’#‘代表到了空节点了完成返回NULL即可。
实现代码:
#include<stdio.h>
#include<stdlib.h>
typedef char BTDataType;
typedef struct BinaryTreeNode//定义二叉树结构体类型
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
BTNode* BinaryTreeCreate(BTDataType *a,int *pi)//以先序遍历的方式构建二叉树
{
if(a[*pi]=='#')
{
(*pi)++;
return NULL;
}
BTNode*root=(BTNode*)malloc(sizeof(BTNode));
if(root==NULL)
{
perror("malloc fail");
return NULL;
}
root->data=a[*pi];
(*pi)++;
root->left=BinaryTreeCreate(a,pi);
root->right=BinaryTreeCreate(a,pi);
return root;
}
void Inorder(BTNode*root)//这里只是一个中序遍历
{
if(root==NULL)
{
return;
}
Inorder(root->left);
printf("%c ",root->data);
Inorder(root->right);
}
int main()
{
char str[100];
scanf("%s",str);
int i=0;
BTNode*root=BinaryTreeCreate(str,&i);
Inorder(root);
return 0;
}
小结:
1、利用分治的思想,逐层化解问题
2、多画递归展开图看底层的递归函数是怎样向上返回的
3、malloc结点时注意括号内是申请多少个字节,而不是个数
好的本次的分享就这么多啦
end