https://leetcode.cn/problems/univalued-binary-tree/description/
bool isUnivalTree(struct TreeNode* root) {
//判断节点是否为空
if(root==NULL)
{
return true;
}
//左孩子存在并且值不等于其父节点值时,返回false
if(root->left && root->left->val != root->val)
{
return false;
}
//右孩子存在并且值不等于其父节点值时,返回false
if(root->right && root->right->val != root->val)
{
return false;
}
//递归左右子树,只有都为单值二叉树时,返回false
return isUnivalTree(root->left) && isUnivalTree(root->right);
}
https://leetcode.cn/problems/same-tree/description/
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);
}
https://leetcode.cn/problems/symmetric-tree/description/
利用递归和镜像比较的特性,将对称树判断转化为特殊的两棵树比较问题。
1. 对称二叉树的核心是判断左子树与右子树是否镜像对称
2. 镜像对称的判断通过改造 "相同树" 的逻辑实现:
3. 具体步骤:
4. 对原树调用时,只需检查其左子树与右子树是否镜像对称
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->right) && isSameTree(p->right,q->left);
}
bool isSymmetric(struct TreeNode* root) {
return isSameTree(root->left,root->right);
}
https://leetcode.cn/problems/subtree-of-another-tree/description/
判断 subRoot 是否为 root 的子树,即检查 root 中是否存在与 subRoot 完全相同的子树
通过递归遍历主树的每个节点,将每个节点作为子树根节点与目标子树进行比对,一旦找到匹配则返回 true。
递归逻辑:
利用 isSameTree 函数(相同二叉树)检查两棵树是否完全相同
typedef struct TreeNode TreeNode;
bool isSameTree(TreeNode* p,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/binary-tree-preorder-traversal/description/
通过先获取树的大小来精确分配内存,再利用递归按前序规则遍历并存储节点值,最终返回完整的遍历结果数组。
1.前序遍历顺序为:根节点 → 左子树 → 右子树
2.实现步骤:
3.使用指针记录数组填充位置,确保递归过程中正确更新索引
typedef struct TreeNode TreeNode;
//二叉树节点个数
int BinaryTreeSize(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
//前序遍历
//传下标的指针,在递归过程中能够改变
void PreOrder(TreeNode* root,int* arr,int* pi)
{
if(root==NULL)
{
return;
}
arr[(*pi)++]=root->val;
PreOrder(root->left,arr,pi);
PreOrder(root->right,arr,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
//*returnSize表示数组元素个数,也就是二叉树节点个数
*returnSize = BinaryTreeSize(root);
int* arr=(int*)malloc(sizeof(int)*(*returnSize));
int i=0;
PreOrder(root,arr,&i);
return arr;
}
https://leetcode.cn/problems/binary-tree-inorder-traversal/description/
通过先获取树的大小来精确分配内存,再利用递归按中序规则遍历并存储节点值,最终返回完整的遍历结果数组。
1.中序遍历顺序为:左子树 → 根节点 → 右子树
2.实现步骤:
3.使用指针记录数组填充位置,确保递归过程中正确更新索引
typedef struct TreeNode TreeNode;
//二叉树节点个数
int BinaryTreeSize(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
//传下标的指针,在递归过程中能够改变
void InOrder(TreeNode* root,int* arr,int* pi)
{
if(root==NULL)
{
return;
}
InOrder(root->left,arr,pi);
arr[(*pi)++]=root->val;
InOrder(root->right,arr,pi);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
//*returnSize表示数组元素个数,也就是二叉树节点个数
*returnSize = BinaryTreeSize(root);
int* arr=(int*)malloc(sizeof(int)*(*returnSize));
int i=0;
InOrder(root,arr,&i);
return arr;
}
https://leetcode.cn/problems/binary-tree-postorder-traversal/description/
通过先获取树的大小来精确分配内存,再利用递归按中序规则遍历并存储节点值,最终返回完整的遍历结果数组。
1.中序遍历顺序为:左子树 → 右子树 → 根节点
2.实现步骤:
3.使用指针记录数组填充位置,确保递归过程中正确更新索引
typedef struct TreeNode TreeNode;
//二叉树节点个数
int BinaryTreeSize(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
//传下标的指针,在递归过程中能够改变
void PostOrder(TreeNode* root,int* arr,int* pi)
{
if(root==NULL)
{
return;
}
PostOrder(root->left,arr,pi);
PostOrder(root->right,arr,pi);
arr[(*pi)++] = root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
//*returnSize表示数组元素个数,也就是二叉树节点个数
*returnSize=BinaryTreeSize(root);
int* arr=(int*)malloc(sizeof(int)*(*returnSize));
//按后序遍历将二叉树中的数据存储在数组
int i=0;
PostOrder(root,arr,&i);
return arr;
}
https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef
通过递归复用先序遍历的逻辑构建二叉树,再用递归完成中序遍历,清晰映射二叉树的递归特性
1. 数据结构定义:定义二叉树节点结构(含数据域、左子树指针、右子树指针)
2. 节点创建:实现buyNode
函数,动态分配节点内存并初始化(数据域赋值,左右指针置空)
3. 二叉树构建(核心):
4. 中序遍历:递归实现左子树→根节点→右子树的遍历顺序,打印节点数据
5. 主流程:
#include <stdio.h>
#include <stdlib.h>
//定义二叉树节点结构
typedef struct BinaryTreeNode{
char data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
//申请新节点
BTNode* buyNode(char x)
{
BTNode* newnode=(BTNode*)malloc(sizeof(BTNode));
if(newnode==NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data=x;
newnode->left=newnode->right=NULL;
return newnode;
}
//构建二叉树
BTNode* creatBinaryTree(char* arr,int* pi)
{
if(arr[*pi]=='#')
{
(*pi)++;
return NULL;
}
BTNode* root=buyNode(arr[(*pi)++]);
root->left=creatBinaryTree(arr, pi);
root->right=creatBinaryTree(arr, pi);
return root;
}
//中序遍历
void InOrder(BTNode* root)
{
if(root==NULL)
{
return;
}
InOrder(root->left);
printf("%c ",root->data);
InOrder(root->right);
}
int main() {
//输入字符串存储起来
char arr[100];
scanf("%s",arr);
//按前序遍历构建二叉树
int i=0;
BTNode* root = creatBinaryTree(arr, &i);
//中序遍历
InOrder(root);
return 0;
}
对任意一棵二叉树,如果度为 0 的节点个数为 n0 ,度为 2 的分支节点个数为 n2 ,则有 n0 = n2 + 1
证明上述性质: 假设⼀个二叉树有 a 个度为2的节点, b 个度为1的节点,c 个叶节点,则这个二叉树的边数是 2a+b 另一方面,由于共有 a+b+c 个节点,所以边数等于 a+b+c-1 结合上面两个公式: 2a+b = a+b+c-1 ,即: a = c - 1
根据上面二叉树的性质,完成以下题目
1. 某二叉树共有 399 个结点,其中有 199 个度为2的结点,则该二叉树中的叶子结点数为(200)
叶子节点(即度为0的节点)= 199(度为2的节点)+ 1 = 200
2.在具有 2n 个结点的完全二叉树中,叶子结点个数为( n )
3.⼀棵完全二叉树的结点数位为531个,那么这棵树的高度为( 10 )
总结点个数 n = 2 ^h - 1
当 h = 9 时,最接近531,同时也比532小,所以高度为 10
4.⼀个具有767个结点的完全二叉树,其叶子结点个数为(384)
如果用上一题的思路 n = 2 ^h - 1
当 h = 9 时,最接近767,同时也比767小,767-511=256,这种方法是错误的,因为完全二叉树出了最后一层为叶子节点外,最后一层的上一层仍有叶子节点。
链式结构二叉树题目
1.某完全二叉树按层次输出(同⼀层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为 ABDHECFG
2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为 E
前序遍历第一个节点即为该二叉树根节点,在它左边的节点为它的左子树,右边为右子树
3.设⼀课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为ABCDE
后续遍历最后一个节点即为该二叉树根节点,在它左边的节点为它的左子树,右边为右子树
4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同⼀层从左到右)的序列 ABCDEF
前序遍历根节点有边第一个节点为左子树根节点
后序遍历根节点左边第一个节点为右子树根节点
本文围绕二叉树 OJ 习题展开,涵盖了单值二叉树、相同二叉树、对称二叉树、子树判断及遍历等经典问题。通过递归等核心思想,解析了各题的解题思路与实现逻辑,帮助读者掌握二叉树的特性及常见操作,为应对同类问题提供了清晰的思路与方法。
如果大家在练习中发现新的解题角度,或是有没搞懂的知识点,欢迎在评论区留言讨论。后续我也会持续更新数据结构相关的 OJ 解析,咱们一起在刷题中夯实基础,稳步进阶!