【数据结构】“链式二叉树”OJ练习与递归

欢迎访问!与黎明同行的主页和ta的getti代码仓库

下面是今天的内容

在这里插入图片描述


请添加图片描述

1. 二叉树销毁

  • 利用分而治之的思想可转化为:
    • 子问题:左右子树的销毁。
  • - 返回条件(最小规模子问题):左/右子树为空。
    先销毁根再销毁左右——后序查找
实现
void destory(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	} 
	destory(root->left);
	destory(root->right);
	free(root);
	//形参改变不会改变实参,故在函数外置空
}

2. 二叉树查找值为x的值

  • 子问题:左/右子树是否为x
  • 返回条件
    • 找到x返回该地址;
    • 左子树找不到去右子树找;
    • 右子树找不到返回空;
  • 注意:要返回地址,所以每次栈帧销毁都要接收返回值,直到回归第一层。
实现
BTNode* FreeFind(BTNode* root,BTDataType x)
{
	//遍历->找到后即返回在函数中接收->前序
	if (root == NULL)
	{
		return;
	}
	if (root->val == x)
	{
		return root;
	}
	BTNode* ret = NULL;
	ret = FreeFind(root->left, x);
	if (ret)
		return ret;		
	ret = FreeFind(root->right, x);
	if (ret)
		return ret;		
	return NULL;	//左右都没找到
}

3. 相同的树

题目:100.相同的树

给你两棵二叉树的根节点 pq ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

  • 最小递归子问题:
  • 遍历
  • 根是否相同
  • 左右子树是否相同
  • 返回条件:
  • 同时为空返回true(子树相同)
  • 接下来有其中一端为NULL的情况,所以不可比较val
  • 有一个为空返回flase
  • 比较val是否相同,不相等则返回false
    - 相同返回true
  • 注意:在该题中要求子树末端也必须得相同
实现
/**
 * 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);
}

![[Pasted image 20230916095543.png]]

4. 对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

  • 沿用上一题的方法,可以将其改为从第二层开始两子树的左右-右左子树相同的问题。
  • 最小递归子问题:
  • 左子树的左值是否等于右子树右值
  • 左子树的右值是否等于右子树左值
  • 返回条件:
  • 全为空返回false;
  • 相同返回true;
  • 不满足子问题返回false;
实现
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);
}

5. 二叉树的前\中\后序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

在线编程中属于接口型(另一个是io型,自己编程)

  • 题目分析
  1. int* returnSize 返回的是数组大小,形参的改变改变不了实参,故传递指针类型 。
  2. 题目值类型为int* ,由于开辟的空间名可自己定义,故返回数组名。
  3. 我们在内部定义局部变量来放malloc过来的空间
    开辟空间大小TreeSize
  4. 将树中元素按前序放入数组中,中序后序遍历与前序同理(前序方法在另一篇文章中已经讲过,故不在此赘述前中后序
    5.最后将n赋值给*TreeSize并返回数组a;
实现
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int  TreeSize(struct TreeNode* root)
{
    return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
}
void preorder(struct TreeNode* root,int* a,int* pi)
{
    if(root==NULL)
        return ;
    a[(*pi)++]=root->val;	//前序
    preorder(root->left,a,pi);
   // a[(*pi)++]=root->val;	//中序    
  	preorder(root->right,a,pi);
   // a[(*pi)++]=root->val;	//后序
  	
}

int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
    int n=TreeSize(root);
    int* a=(int*)malloc(sizeof(int)*n);
    int j=0;    
    //不能重复malloc申请空间,所以写一个子函数用来递归
    preorder(root,a,&j);
    *returnSize=n;
    return a;
}

6. 翻转二叉树

题目:翻转二叉树

  • 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
    分析:

最小递归子问题:左右两子树交换(Swap)
返回条件:将每个节点遍历完后是NULL返回。前序遍历
综上,该程序可大致理解为在前序遍历中的交换左右子树问题

实现
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
void Swap(struct TreeNode** p1,struct TreeNode** p2)
{
   struct TreeNode* tmp=NULL;
    tmp=*p1;
    *p1=*p2;
    *p2=tmp;
}
void PreOrder(struct TreeNode* root)
{
    if(root==NULL)
        return ;
    Swap(&(root->left),&(root->right));
    PreOrder(root->left);
    PreOrder(root->right);
}
struct TreeNode* invertTree(struct TreeNode* root)
{
    PreOrder(root);
    return root;
}

7. 另一颗子树

给你两棵二叉树 rootsubRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

题目分析:
最小子问题:

判断当前节点下的子树是否相等,见上文中100.相同的树 问题。
返回条件:
前序遍历每个节点,若相同则判断当下节点子树是否相等

实现
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
bool IsSameTree(struct TreeNode* root, struct TreeNode* subRoot)
{
    //全为空
    if(root==NULL && subRoot==NULL)
        return true;
    //一个为空
    if(root==NULL || subRoot==NULL)
            return false;
    //都不为空
    if(root->val != subRoot->val)
            return false;
    return IsSameTree(root->left,subRoot->left)
        && IsSameTree(root->right,subRoot->right);
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root == NULL)
        return false;
    if(root->val==subRoot->val)
    {
        if(IsSameTree(root,subRoot))
            return true;
    }
    return isSubtree(root->left,subRoot)
        || isSubtree(root->right,subRoot);
}

8. 层序遍历——队列

先进先出
引入队列结构,将int类型该为树的节点类型
.h在预处理阶段不会被处理。.h文件回去再.cpp文件展开,所以放在结构体声明下面

  • 实现过程

root=1时,打印front=1,左右不为空,左2右3入队列,删除队头元素1
root=2时,打印front=2,左右不为空,左4右5入队列,删除队头元素2
root=3时,打印front=3,左右为空,删除队头元素3
root=4时,打印front=4,右不为空,右6入队列,删除队头元素4
………………
![[Drawing 2023-09-23 16.03.53.excalidraw.png]]

void LevelOrder(BTNode* root)
{
	Que q;
	QueInit(&q);
	
	if (root)
		QuePush(&q, root);
	while (!QueEmpty(&q))
	{
		BTNode* front = QueFront(&q);
		printf("%d",front->val);
		if (front->left)
			QuePush(&q, front->left);
		if (front->right)
			QuePush(&q, front->right);
		QuePop(&q);
	}
	printf("\n");
	QueDestory(&q);
}

9. 是否为完全二叉树

完全二叉树:前n-1层都是连续的(走层序遍历非空节点连续)
入到空后面一定没有非空
遍历,有空且后面没有非空时为完全二叉树。

bool TreeComplete(BTNode* root)
{
	Que q;
	QueInit(&q);

	if (root)
		QuePush(&q, root);
	while (!QueEmpty(&q))
	{
		BTNode* front = QueFront(&q);
	//全部入队列,直到遇到NULL停止	
		if (front==NULL)
			break;
		QuePush(&q, front->left);
		QuePush(&q, front->right);
		QuePop(&q);
	}
	//继续入队,遇到非空即不是完全二叉树
	while (!QueEmpty(&q))
	{
		BTNode* front = QueFront(&q);
		QuePop(&q);
		if (front != NULL)
		{
			QueDestory(&q);
			return false;
		}
	}
	QueDestory(&q);
	return true;
}

10. 求树的高度

高度——就是最深的一层

//(1)
int treeheight(btnode* root)
{
	if (root == null)
		return 0;
	return treeheight(root->left) > treeheight(root->right) ?
		treeheight(root->left) + 1 : treeheight(root->right) + 1;
}

//多次调用计算,效率及其地下低下,因为在调用时进行了两次递归,非常差

//(2)
int Treeheight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftheight = Treeheight(root->left);
	int rightheight = Treeheight(root->right);

	return  leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}
//(3)
int Treeheight(BTNode* root)
{
	if (root == NULL)
		return 0;

	return  fmax(Treeheight(root->left),Treeheight(root->right)) + 1;
}

fmax记得包含头文件#include<math.h>

11. [KY11 二叉树遍历]

题目 11. KY11 二叉树遍历
![[Pasted image 20230925193204.png]]

分析

  • 根据题目要求,对字符串先序遍历(根-左-右)创建二叉树,如图所示;
  • 当遇到空#时为空,返回NULL
  • 之后按照后续遍历将二叉树打印出来

![[Pasted image 20230925193117.png]]

代码

#include <stdio.h>
#include <stdlib.h>

typedef char BTDataType;
//二叉树结构体
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType val;
}BTNode;
//创建树结构
BTNode* CreatTree(char* str, int* pi)	
{
	if (str[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->val = str[*pi];
	(*pi)++;
	//先序插入
	root->left = CreatTree(str, pi);
	root->right = CreatTree(str, pi);
	return root;
}
//中序输出
void Inorder(BTNode* root)
{
	if (root == NULL)
		return;
	Inorder(root->left);
	printf("%c ", root->val);
	Inorder(root->right);
}

int main()
{
	char str[100];
	scanf("%s", str);

	int i = 0;
	BTNode* root = CreatTree(str, &i);
	//输入下标地址,便于在函数递归调用时可以使用
	Inorder(root);
	return 0;
}

在这里插入图片描述

感谢未来大佬们的光顾,创作不易,还请给个免费的赞哦~~❤️❤️❤️

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值