二叉树应用实践
目录
单值二叉树(力扣)
代码实现:
核心逻辑:
相同的树
代码实现:
核心逻辑:
对称的树(由相同的树衍生)
代码实现:
核心逻辑:
另一棵树的子树
核心逻辑:
代码实现:
二叉树的前中后序遍历(以前为例)
代码实现:
核心逻辑:
注意:
二叉树遍历(牛客):
代码实现:
基本逻辑:
单值二叉树(力扣)
https://leetcode.cn/problems/univalued-binary-tree/description/
代码实现:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:bool isUnivalTree(TreeNode* root) {if(root==NULL){return true;}if ((root->left != NULL && root->val != root->left->val) || (root->right != NULL && root->val != root->right->val)) {return false;
}return isUnivalTree(root->left)&&isUnivalTree(root->right);}
};
核心逻辑:
- 空树处理:如果根节点
root
为NULL
(空树),直接返回true
,因为空树可视为单值二叉树。 - 当前节点与子节点值的检查:
- 若左子节点存在且其值与当前节点值不同,或者右子节点存在且其值与当前节点值不同,说明不是单值二叉树,返回
false
。
- 若左子节点存在且其值与当前节点值不同,或者右子节点存在且其值与当前节点值不同,说明不是单值二叉树,返回
- 递归检查子树:递归地检查左子树和右子树是否为单值二叉树,只有当左子树和右子树都为单值二叉树时,整个树才是单值二叉树,返回
true
。
相同的树
https://leetcode.cn/problems/same-tree/description/
代码实现:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:bool isSameTree(TreeNode* p, TreeNode* q) {if(p==NULL&&q==NULL){return true;}if(p==NULL||q==NULL){return false;}if(q->val!=p->val){return false;}return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);}
};
核心逻辑:
-
基础情况判断:
- 如果两棵树的当前节点都为
NULL
(空),返回true
(空树视为相同) - 如果其中一棵树的当前节点为
NULL
而另一棵不为NULL
,返回false
(结构不同)
- 如果两棵树的当前节点都为
-
节点值判断:
- 如果当前节点的值不相等,返回
false
(值不同)
- 如果当前节点的值不相等,返回
-
递归判断子树:
- 递归判断左子树是否相同
- 递归判断右子树是否相同
- 只有左右子树都相同时,才返回
true
对称的树(由相同的树衍生)
代码实现:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {if(p==NULL&&q==NULL){return true;}if(p==NULL||q==NULL){return false;}if(q->val!=p->val){return false;}return isSameTree(p->left,q->right)&&isSameTree(p->right,q->left);}bool isSymmetric(TreeNode* root) {return isSameTree(root->left,root->right);}
};
核心逻辑:
- 定义
isSameTree
函数的变种,比较规则改为:判断一棵树的左子树与另一棵树的右子树、一棵树的右子树与另一棵树的左子树是否相同。 - 在
isSymmetric
函数中,通过调用上述变种isSameTree
,比较根节点的左子树和右子树是否满足对称条件,以此确定整棵树是否对称。
另一棵树的子树
https://leetcode.cn/problems/subtree-of-another-tree/description/
核心逻辑:
-
判断两棵树是否完全相同(
isSameTree
函数)- 若两棵树的当前节点都为空,返回
true
- 若其中一棵为空另一棵不为空,返回
false
- 若节点值不同,返回
false
- 递归检查左子树和右子树是否都相同
- 若两棵树的当前节点都为空,返回
-
判断子树关系(
isSubtree
函数)- 若主树
root
为空,返回false
(空树不可能包含非空子树) - 若当前节点开始的子树与
subRoot
相同,返回true
- 否则递归检查
root
的左子树或右子树是否包含subRoot
- 若主树
代码实现:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {if(p==NULL&&q==NULL){return true;}if(p==NULL||q==NULL){return false;}if(q->val!=p->val){return false;}return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);}bool isSubtree(TreeNode* root, 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/
中序遍历:https://leetcode.cn/problems/binary-tree-inorder-traversal/description/
后序遍历:https://leetcode.cn/problems/binary-tree-postorder-traversal/description/
代码实现:
/*** 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().*/typedef struct TreeNode TreeNode;
int Treesize(TreeNode*root)
{if(root==NULL){return 0;}return 1+Treesize(root->left)+Treesize(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=Treesize(root);int*arr=(int*)malloc(sizeof(int)*(*returnSize));int i=0;preorder(root,arr,&i);return arr;}
核心逻辑:
-
TreeNode 结构体
定义了二叉树节点的结构,包含节点值val
和左右子节点指针left
、right
。 -
Treesize 函数
- 功能:计算二叉树的节点总数(递归实现)。
- 逻辑:空节点返回 0;非空节点返回「1(当前节点)+ 左子树节点数 + 右子树节点数」。
- 作用:确定前序遍历结果数组需要申请的内存大小。
-
preorder 函数
- 功能:递归执行前序遍历,将节点值存入数组。
- 参数:
root
:当前遍历的节点arr
:存储结果的数组pi
:指向数组索引的指针(用于在递归中共享当前填充位置)
- 逻辑:先存储当前节点值,再递归遍历左子树,最后递归遍历右子树。
-
preorderTraversal 函数(主函数)
- 步骤:
- 调用
Treesize
计算节点总数,通过returnSize
传出(供调用者获取数组长度)。 - 根据节点总数用
malloc
动态申请数组内存。 - 初始化索引
i=0
,调用preorder
填充数组。 - 返回填充好的数组。
- 调用
- 步骤:
注意:
- 内存管理:数组通过
malloc
申请,调用者需在使用后用free
释放,避免内存泄漏。 - 递归限制:对于深度极大的二叉树(如链式结构),递归可能导致栈溢出,此时需改用迭代方式实现。
- 参数要求:
returnSize
必须是有效的 int 指针(不能为 NULL),否则会导致解引用错误。
二叉树遍历(牛客):
https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef
代码实现:
//二叉树链式结构
#include<stdio.h>
typedef struct TreeNode{int data;struct TreeNode*left;struct TreeNode*right;
}TreeNode;TreeNode*BuyNode(char ch)
{TreeNode*node=(TreeNode*)malloc(sizeof(TreeNode));if(node==NULL){exit(1);}node->data=ch;node->left=node->right=NULL;return node;}
//创建二叉树
TreeNode*createTree(char*arr,int *pi)
{if(arr[*pi]=='#'){(*pi)++;return NULL;}TreeNode*root=BuyNode(arr[*pi]);(*pi)++;root->left=createTree(arr, pi);root->right=createTree(arr, pi);return root;}
void inorder(TreeNode*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;TreeNode*root=createTree(arr, &i);//二叉树的中序遍历inorder(root);
}
加上销毁
// 销毁二叉树(释放所有节点内存)
void DestroyTree(TreeNode* root) {if (root == NULL) {return;}DestroyTree(root->left); // 先销毁左子树DestroyTree(root->right); // 再销毁右子树free(root); // 最后释放当前节点
}
基本逻辑:
- TreeNode 结构体:定义二叉树节点,包含数据域
data
和左右子节点指针。 - BuyNode 函数:创建新节点,为节点分配内存并初始化。
- createTree 函数:根据前序遍历字符串(含
#
表示空节点)递归构建二叉树。 - inorder 函数:递归实现二叉树的中序遍历(左 → 根 → 右)并打印节点值。
- main 函数:读取输入的前序字符串,构建二叉树并执行中序遍历