【数据结构与算法】二叉树题目很难?一句话秒杀基础二叉树题目_二叉树难不难

本文详细介绍了二叉树的基本概念,特别是链式结构与顺序结构的区别,以及前序、中序和后序遍历的原理与C语言实现。通过递归方法演示了如何遍历整棵树,适合IT技术学习者深入理解数据结构。
摘要由CSDN通过智能技术生成

💛 前情提要💛

本章节是数据结构链式二叉树的相关知识~

接下来我们即将进入一个全新的空间,对代码有一个全新的视角~

以下的内容一定会让你对数据结构有一个颠覆性的认识哦!!!

❗以下内容以C语言的方式实现,对于数据结构来说最重要的是思想哦❗

以下内容干货满满,跟上步伐吧~


作者介绍:

🎓 作者: 热爱编程不起眼的小人物🐐
🔎作者的Gitee:代码仓库
📌系列文章&专栏推荐: 《刷题特辑》《C语言学习专栏》《数据结构_初阶》

📒我和大家一样都是初次踏入这个美妙的“元”宇宙🌏 希望在输出知识的同时,也能与大家共同进步、无限进步🌟


📌导航小助手📌

💡本章重点

  • 二叉树链式结构的概念
  • 二叉树的三种遍历方式
  • 🔥算法思想

**🍞一.**二叉树的概念

**🥐Ⅰ.**二叉树链式结构

💡简单来说:

  • 就是用链表去表示一棵二叉树,即用链表去表示元素之间的逻辑关系

这里是引用

  • 二叉树链式结构不同于【因为又称为二叉树的顺序结构】

    • 二叉树的链式结构可以存储任意 (包括:普通二叉树,满二叉树,完全二叉树等)
    • 而二叉树的顺序结构存储更多存储的是完全二叉树满二叉树,而不存储普通二叉树,否则会造成空间浪费

👉二叉树可分两种:

  1. 空树
  2. 非空树:根节点、根节点的左子树、根节点的右子树组成(如下图:)

在这里插入图片描述

👉代码实现:

typedef int BTDataType;

typedef struct BinaryTreeNode
{
	struct BinaryTreeNode\* left; 
	struct BinaryTreeNode\* right;
	BTDataType data;
}BTNode;

综上:

  • 不难发现二叉树的定义正是递归式
  • 所以我们正可以通过递归的方式去遍历整个二叉树

✊所以接下来我们就开始实现吧~


**🍞二.**二叉树的遍历

**🥐Ⅰ.**前序遍历

💡前序遍历: 又称为先根遍历

  • 即访问根结点的操作发生在遍历其左右子树之前
  • 简单来说:优先访问根节点,继而访问根节点的左子树,最后再访问根节点的右子树

特别注意:

  • 上述所说的根节点不仅仅指的是整棵树的根节点,也指每一个结点【因为每一个结点都可以当作一个根节点来看待】
  • 因此每一个结点都可以以根节点看待【即一棵完整的树,被拆分成多个子树看待】

在这里插入图片描述

动图示例:

在这里插入图片描述

👉代码实现:

void PrevOrder(BTNode\* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	//访问根结点
	printf("%d ", root->data);
	//访问左子树
	PrevOrder(root->left);
	//访问右子树
	PrevOrder(root->right);
}

👆递归展示:

这里是引用

综上: 每个结点都可以看作一棵树【即拆分成子问题看待】

  • 每次先访问根结点
  • 继而访问左子树,直至访问完全整棵树中的左子树
  • 最后访问右子树,直至访问完全整棵树中的右子树

**🥐Ⅱ.**中序遍历

💡前序遍历: 又称为中根遍历

  • 即访问根结点的操作发生在遍历其左右子树之中(间)
  • 简单来说:先递归遍历完根节点的左子树,而后递归返回时访问根节点,最后再递归访问根节点的右子树

特别注意:

  • 上述所说的根节点不仅仅指的是整棵树的根节点,也指每一个结点【因为每一个结点都可以当作一个根节点来看待】
  • 因此每一个结点都可以以根节点看待【即一棵完整的树,被拆分成多个子树看待】

在这里插入图片描述

动图示例:

在这里插入图片描述

👉代码实现:

void InOrder(BTNode\* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	//访问左子树
	InOrder(root->left);
	//访问根结点
	printf("%d ", root->data);
	//访问右子树
	InOrder(root->right);
}

综上: 每个结点都可以看作一棵树【即拆分成子问题看待】

  • 每次先访问左子树,直至访问完全整棵树中的左子树
  • 继而访问根节点
  • 最后访问右子树,直至访问完全整棵树中的右子树

**🥐Ⅲ.**后序遍历

💡前序遍历: 又称为后根遍历

  • 即访问根结点的操作发生在遍历其左右子树之后
  • 简单来说:优先访问根节点的右子树,继而访问根节点,最后再访问根节点的左子树

特别注意:

  • 上述所说的根节点不仅仅指的是整棵树的根节点,也指每一个结点【因为每一个结点都可以当作一个根节点来看待】
  • 因此每一个结点都可以以根节点看待【即一颗完整的树,被拆分成多个子树看待】

在这里插入图片描述

动图示例:

在这里插入图片描述

👉代码实现:

void PostOrder(BTNode\* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	//访问左子树
	PostOrder(root->left);
	//访问右子树
	PostOrder(root->right);
	//访问根结点
	printf("%d ", root->data);
}


综上: 每个结点都可以看作一棵树【即拆分成子问题看待】

  • 每次先访问左子树,直至访问完全整棵树中的左子树
  • 继而访问右子树,直至访问完全整棵树中的右子树
  • 最后再访问根结点

**🥯Ⅳ.**总结

✨综上:三种二叉树的遍历方式,本质就是调换访问左子树右子树根节点的语句次序,然后程序便会自动递归帮我们访问完整棵树的所有结点啦~

➡️相信大家对三种遍历方式有不一样的看法了吧🧡


**🍞三.**二叉树OJ题

🔥秒杀模板

秒杀口诀:

  • 左右子树之间的逻辑关系➕树的遍历方式
  • 1️⃣左右子树之间的关系:指的是为了达到题目要求的结果,我们需要让左、右子树之间达成什么样的关系【Eg:逻辑关系(&&、||、……)、算数关系(+、-、……)、……】
  • 2️⃣找出逻辑关系后,只需要结合合适的遍历方式,相当于找到通式,便可以通过通式解决题目了

❓具体是怎么运用呢?

✊让我们用题目来实际运用分析吧~


🏷️ 单值二叉树【难度:简单】

🔍题目传送门:

Leetcode:965. 单值二叉树

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树

只有给定的树是单值二叉树时,才返回 true,否则返回 false

  • 示例 1:

这里是引用

输入:[1,1,1,1,1,null,1]
输出:true

  • 示例 2:

这里是引用

输入:[2,2,2,5,2]
输出:false

💡解题关键:

  • 我们只需要遍历二叉树的每一个结点,一一比较每个结点的值是否相同
  • 本题就可以运用我们的秒杀技巧

👉秒杀分析:

  • 此处先找到左、右子树之间的逻辑关系

    • 我们将视角放到整体的树上,只看这个树的左、右子树之间通过怎样的逻辑关系才能实现题目要求(如下:)

这里是引用

➡️如上我们便可发现: 题目需要我们去判断每一个结点的值是否相同,那此时对于上面的树来说,我们就需要判断左子树右子树里的每一个结点是否与根节点的值相同

  • 1️⃣那此时我们便找到合适的遍历方式前序遍历

    • 因为每次遍历下来直接先判断根节点的值是否相同,不相同就可以直接返回false,不再需要递归下去
    • 否则,若用其它遍历方式,就需要在判断完子树的所有结点后,返回的时候才判断根节点

➡️又因为: 需要左子树右子树递归判断完后返回的结果都为true后,整棵树才真正的满足单值二叉树

  • 2️⃣那此时我们便知道左、右子树之间的逻辑关系&&【只有左右俩操作数都满足时,才真正的满足】

👆综上:

  • 秒杀口诀为:&&前序遍历
  • 本质:将每个结点与自己的孩子结点进行比较,看是否相同,一直比较直至递归完整棵树【利用的是:等号具有传递性

特别注意:

  • 当根节点或者二叉树为NULL的时候,就返回true,因为没有值的结点可以不参与判断,有值的才去进行判断
  • 在进行每一个结点与孩子结点比较的时候,需要判断提前孩子结点是否为NULL,因为只有不为NULL才能访问到这个结点的val ;否则会造成非法访问内存

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

:将每个结点与自己的孩子结点进行比较,看是否相同,一直比较直至递归完整棵树【利用的是:等号具有传递性

特别注意:

  • 当根节点或者二叉树为NULL的时候,就返回true,因为没有值的结点可以不参与判断,有值的才去进行判断
  • 在进行每一个结点与孩子结点比较的时候,需要判断提前孩子结点是否为NULL,因为只有不为NULL才能访问到这个结点的val ;否则会造成非法访问内存

[外链图片转存中…(img-evebzGKS-1714274179109)]
[外链图片转存中…(img-sftXOhc0-1714274179109)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值