二叉树的一些练习题

2023-11-20

前言

二叉树的简单题目,通过画栈帧图去理解过程。画一画,走一走递归过程,理解会更加深刻。

二叉树的创建

二叉树先序遍历创建

根据前序遍历的序列"ABD##E#H##CF##G##"

在这里插入图片描述

PreCreat

调用函数,需谨记形参的改变不能改变实参。在对字符串遍历的过程,需要确保每次栈帧中,对应下标是正确的,那么传参是必须传址调用。

看不懂的话,属实没辙,需要自己画一画。每个栈帧相当于一个节点,只有函数返回后,才能把整个树串起来。
你可以这样去理解递进过程:(看实际的二叉树)递进过程做的事情是每个节点找到了自己所在的位置。
返回过程:父子节点手拉手,心连心(皮一皮)

如何看递归展开图:跟着箭头和代码。

在这里插入图片描述

 struct BTNode
{
	int val;
	struct BTNode* left;
	struct BTNode* right;
};

struct BTNode* PreCreat(char* str, int* pi)
{
	if (str[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	struct BTNode* root = (struct BTNode*)malloc(sizeof(struct BTNode));
	root->val = str[(*pi)++];
	root->left = PreCreat(str, pi);
	root->right = PreCreat(str, pi);
	return root;
}
int main()
{
	char str[] = "ABD##E#H##CF##G##";
	int i = 0;
	struct BTNode* root = PreCreat(str, &i);
	return 0;
}

二叉树层次创建

层次创建二叉树。给定层次遍历的结果,将之变成对应的二叉树。
需要用到队列,哪个过程符合先进先出的原则呢?取父节点的过程。
层次遍历结果的字符串为:1234\01、2、3这三个节点很容易串起来,关键在4节点怎么找到它的父节点是2节点,假设后面还有节点,怎么保证后面的每个节点都能对应的上相应的父节点。
通过队列来保证,#表示NULL
在这里插入图片描述

根节点先入队,进入循环。循环结束条件:当前字符串不为'\0'。出队的节点当作父节点,并且按顺序链接左孩子、右孩子并把这两个孩子按顺序入队。重复

在这里插入图片描述

下列代码为伪代码:未把队列的接口函数给出。栈和队列需要的话自己去这个博客里cv一下。

LevelCreat


struct BTNode
{
	char val;
	struct BTNode* left;
	struct BTNode* right;
};

typedef struct BTNode* QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{
	QDataType data;
	struct QListNode* next;

}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* front;
	QNode* rear;
}Queue;

struct BTNode* AollocBTNode(char val)
{
	struct BTNode* root = (struct BTNode*)malloc(sizeof(struct BTNode));
	root->val = val;
	root->left = NULL;
	root->right = NULL;
	return root;
}
struct BTNode* LevelCreat(char* str)
{
	Queue q;
	QueueInit(&q);
	int i = 0;
	struct BTNode* root = AollocBTNode(str[i++]);
	struct BTNode* Reroot = root;

	QueuePush(&q, root);
	//1234
	while (str[i] != '\0')
	{
		root = QueueFront(&q);//取队头元素
		QueuePop(&q);//弹出队头元素
		if (str[i] != '#')
		{
			root->left = AollocBTNode(str[i++]);
			QueuePush(&q, root->left);//左孩子入队
		}
		else
			i++;
		if (str[i] != '\0')
		{
			if (str[i] != '#')
			{
				root->right = AollocBTNode(str[i++]);
				QueuePush(&q, root->right);//右孩子入队
			}
			else
				i++;
		}
	}
	QueueDestroy(&q);
	return Reroot;
}
int main()
{
	char str[] = "ABCDEFG###H";
	struct BTNode* root = LevelCreat(str);
	return 0;
}

二叉树的销毁

什么时候将空间释放?肯定是最后一次经过该节点的时候,那么得选择后序遍历。
(前序:第一次经过某个节点,中序:第二次经过某个节点,后序:最后一次经过某个节点)
不管是第一次,还是第二次经过某个节点,都不能释放,因为它递归还没执行到最后,如果先把节点释放了,它继续进行递归就会找不到它的孩子们了。
下面给了两种形式的,一个是二级指针形式,一个是一级指针形式的。
二级指针形式是传址调用,释放后对应的指针(指向每个节点的指针)都会置为NULL
一级指针形式是传值调用,释放后对应的指针仍然指向该地址,但没有权限访问。为了避免非法访问,调用完该函数后,主函数中还需要执行root = NULL;

BinaryTreeDestory

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
		return;
	BinaryTreeDestory(&((*root)->left));
	BinaryTreeDestory(&((*root)->right));
	free(*root);
	*root = NULL;
}
//主函数调用BTDestory后还需要执行 root = NULL;
void BTDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BTDestory(root->left);
	BTDestory(root->right);
	free(root);
}
//伪代码:
int main()
{
     BTDestory(root);
     root = NULL;
}

二叉树求节点个数

看图理解。 函数中的+1这个1是当前栈帧中是否有节点

在这里插入图片描述

BinaryTreeSize

int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

二叉树叶子节点个数

通过递归去走完每一个节点,走到特定的节点(叶子节点),需要带回返回值。
和上面一题差不多。叶子节点:没有左孩子也没有右孩子的节点。
需要判断:只有是叶子节点的时候才返回1,当为NULL时返回0,其它情况返回之前的结果。
可以像我上面画的图一样,自己动手画一画,去理解其中过程。

BinaryTreeLeafSize

int BinaryTreeLeafSize(BTNode* root)
{
	if (root && root->left == NULL && root->right == NULL)
		return 1;
	if (root == NULL)
		return 0;
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

二叉树求高度

随便给你一颗树,你怎么求这个树的高度呢?
分治思想:在某节点,你知道该节点的左子树、右子树的高度,取其中最大值,再+1就能得到当前节点总共的高度。每一棵子树都是这样得到的。
在代码具体实现的时候,是先知道最下面的高度,返回后才能知道上面节点的高度。

在这里插入图片描述
在这里插入图片描述

BinaryBTHeight

int BinaryBTHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int h1 = BinaryBTHeight(root->left);
	int h2 = BinaryBTHeight(root->right);
	return h1 > h2 ? h1 + 1 : h2 + 1;
}

二叉树第k层的节点数

假设k为3,根据下图所示,当k==1时,就是我们所要找的层,因此在这里就可以返回了。

在这里插入图片描述

如果k为5,不会到k==1,会先碰到NULL返回


在这里插入图片描述

BinaryTreeLevelKSize

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->left, k - 1) +
		BinaryTreeLevelKSize(root->right, k - 1);
}

检测两颗二叉树是否完全相同

LeetCode.100.相同的树

写的时候要直接写能得出结果的,就是说当两棵树不相同的时候,直接返回false,而不判断是否相同,因为当前节点相同了,但是它的孩子不一定相同。不相等时直接返回false简单粗暴。

会出现下面两种情况:①一棵树为NULL,另一棵为非空,这种情况是false。②两棵树的节点都为NULL才能说是true。条件写的时候②要放在上面,①要放在下面。因为if(p == NULL || q == NULL)这个条件包含了p == NULL && q == NULL这种情况

isSameTree

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p == NULL && q == NULL)
    return true;
    if(p == NULL || q == NULL)
    return false;
    if(p && q && p->val != q->val)
    return false;
    return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}

另一棵树的子树

LeetCode.572.另一棵树的子树
在这里插入图片描述

还记的上面一题写的相同的树吗?在这一题可以使用吗?当然可以,而且这样写会非常简单。
root这棵树去遍历它的每个节点,每个节点都当作新子树的根subRoot这棵树判断是否为相同的树。相同了就可以返回true,这种情况下是不需要遍历完所有的节点。如果遍历完所有的节点,都没相同的子树才能说false。因此返回的逻辑关系是“或”

isSubtree

 bool isSameTree(struct TreeNode* p, struct TreeNode* q)
 {
	 if (q == NULL && p == NULL)
		 return true;
	 if (q == NULL || p == NULL)
		 return false;
	 if (q->val != p->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);

}

二叉树的翻转

找到规律就很简单。每个节点的孩子交换,就能完成翻转。
在这里插入图片描述

invertTree

struct TreeNode* invertTree(struct TreeNode* root)
{
    if (root == NULL)
        return NULL;
    struct TreeNode* tmp = root->left;
    root->left = root->right;
    root->right = tmp;
    invertTree(root->left);
    invertTree(root->right);
    return root;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

二叉树的一些练习题 的相关文章

随机推荐

  • 第4章 数据库应用系统功能设计与实施

    4 1软件体系结构与设计过程 4 1 1软件体系结构 软件体系结构又称软件架构 软件体系结构 构件 连接件 约束 其中 构件 Component 是组成系统的具有一定独立功能的不同粒度的程序模块 独立程序或软件子系统 是组成软件的系统元素
  • 关于jupyter notebook 更换环境的方法

    一 查看conda现有的环境 打开Anaconda Powershell Prompt 输入以下代码 conda env list 查看环境变量 可以看到如下已经配置的环境变量 二 激活现有环境 在Anaconda Powershell P
  • 使用react-markdown来解析markdown语法

    什么是 react markdown 组件 它是一个基于React的Markdown 编辑器组件 可以对代码进行高亮显示 链接 github网址 react markdown的安装 yarn add react markdown 引入 im
  • 链语BTChat力推“加密+社交” 引领区块链新社交时代

    近些年来互联网的发展日新月异 大数据化 人工智能 物联网这些都在成为人们生活中触手可及的东西 而区块链技能则被认为是继互联网之后最具颠覆性的创新技术 此前区块链技术在金融服务业 游戏 供应链等不同的产业中都有着广泛应用 同样的对于社交平台而
  • wsfuzzer video

    http www neurofuzz com modules software vidz php
  • 14-4_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP组播

    文章目录 1 UDP组播的特性 2 UDP 组播实例程序的功能 3 组播功能的程序实现 4 源码 4 1 可视化UI设计 4 2 mainwindow h 4 3 mainwindow cpp 1 UDP组播的特性 下图简单表示了组播的原理
  • Golang连接Jenkins获取Job Build状态及相关信息

    文章目录 1 连接Jenkins 2 controller 3 module 4 router 5 效果展示 第三方包 gojenkins 方法文档 gojenkins docs 实现起来很简单 利用第三方库 连接jenkins 调用相关方
  • flutter解决键盘顶起页面

    前言 flutter中解决键盘顶起页面的问题 flutter 1 Scaffold resizeToAvoidBottomPadding return Scaffold resizeToAvoidBottomPadding false 解决
  • 使用OpenCV与深度学习从视频和图像中精准识别人脸: Python实践指南

    第一部分 引言与背景 人脸识别已经成为了当代技术领域中最热门和广泛应用的话题之一 从智能手机的解锁功能到机场的安全检查 人脸识别技术无处不在 在这篇文章中 我们将使用Python中的OpenCV库和深度学习模型 深入探讨如何从视频和图像中精
  • js 对数组对象进行排序

    let listData id 1 name 测试1 presenttime 1557883600000 id 2 name 测试2 presenttime 1580751813000 id 3 presenttime 1561448381
  • svn版本号,命令中-r 2和@2的区别

    问题 假设有一个svn repository是 svn 192 168 2 6 project 在版本1 20的svn里 存在 svn 192 168 2 6 project branches branch test 在版本21时 由于br
  • BUUCTF-Web-命令执行-[ACTF2020 新生赛]Exec

    BUUCTF Web 命令执行 ACTF2020 新生赛 Exec 题目链接 BUUCTF 类型 命令注入 知识点 命令拼接符 解题过程 这道题目比较简单 打开发现是一个ping命令执行页面 使用post接受参数 测试命令拼接符 发现未进行
  • CMW500测试设置及问题处理

    测试CATM1需要打开eMTC Auto Mode 最新的U BLOX R510S模块 这里需要设置为RMC模式 设置为eMTC Auto Mode会出现连接后就断开的情况 没法测试 Measure subframe设置为5 不同的band
  • Kubernetes生产实践系列之三十一:Kubernetes基础技术之CPU资源的调度和管理(CFS)

    一 前言 在使用Kubernetes的过程中 我们看到过这样一个告警信息 K8S 告警主题 CPUThrottlingHigh 告警级别 warning 告警类型 CPUThrottlingHigh 故障实例 告警详情 27 throttl
  • android bluetooth UUID蓝牙查询表

    UUID是 Universally Unique Identifier 的简称 通用唯一识别码的意思 对于蓝牙设备 每个服务都有通用 独立 唯一的UUID与之对应 也就是说 在同一时间 同一地点 不可能有两个相同的UUID标识的不同服务 以
  • .Net C# 使用 IKVM 调用 Java 代码

    相关开源库 https github com ikvm revived 版本号 Net 6 JDK 8 IKVM 8 2 1 IKVM 在 8 2 0 版本中新增加 IkvmReference 在 MSBuild 中配置 自动帮你编译jar
  • 虚拟机打开vim文件以后退出方式

    如果是vi 则 Esc 退出编辑模式 输入以下命令 wq 保存后退出vi 若为 wq 则为强制储存后退出 常用 w 保存但不退出 常用 w 若文件属性为 只读 时 强制写入该档案 q 离开 vi 常用 q 若曾修改过档案 又不想储存 使用
  • python制作查询工具发给别人使用_Python 制作查询商品历史价格的小工具

    一年一度的双十一就快到了 各种砍价 盖楼 挖现金的口令将在未来一个月内充斥朋友圈 微信群中 玩过多次双十一活动的小编表示一顿操作猛如虎 一看结果2毛5 浪费时间不说而且未必得到真正的优惠 双十一电商的 明降暗升 已经是默认的潜规则了 打破这
  • 为何在新建STM工程中全局声明两个宏

    在uVision中新建STM32工程后 需要从STM32标准库中拷贝标准外设驱动到自己的工程目录中 此时需要在工程设置 gt C C 选项卡下的Define文本框中键入这两个全局宏定义 STM32F40 41xxx USE STDPERIP
  • 二叉树的一些练习题

    前言 二叉树的简单题目 通过画栈帧图去理解过程 画一画 走一走递归过程 理解会更加深刻 二叉树练习题 前言 二叉树的创建 二叉树先序遍历创建 PreCreat 二叉树层次创建 LevelCreat 二叉树的销毁 BinaryTreeDest