目录
习题一:查找值为x的节点,并返回节点指针。
习题二:相同的树
习题三:二叉树的前序遍历
习题四:另一棵树的子树
习题五:二叉树遍历
函数声明如下:BTNode* BinaryTreeFind(BTNode* root, int x);
以下图的树为例:
分析:先找到树的根,再找左子树,最后找右子树。
BTNode* BinaryTreeFind(BTNode* root, int x) {
//第一种情况(当前节点为空)(终止条件)
if (root == NULL) {
return NULL;
}
//第二种情况(当前节点存储的数值为x,则返回当前节点)
if (root->data == x) {
return root;
}
//对左子树进行查找
BTNode* lret = BinaryTreeFind(root->left, x);
if (lret) {
return lret;
}
//对右子树进行查找
BTNode* rret= BinaryTreeFind(root->right, x);
if (rret) {
return rret;
}
};
改正代码:
BTNode* BinaryTreeFind(BTNode* root, int x) {
//第一种情况(当前节点为空)(终止条件)
if (root == NULL) {
return NULL;
}
//第二种情况(当前节点存储的数值为x,则返回当前节点)
if (root->data == x) {
return root;
}
//代码运行到此处,表示节点存储的数值不为x,需要继续对其余节点(左子树、右子树)进行查找
//对左子树进行查找
BTNode* lret = BinaryTreeFind(root->left, x);
if (lret) {
return lret;
}
//对右子树进行查找
BTNode* rret= BinaryTreeFind(root->right, x);
if (rret) {
return rret;
}
return NULL;
};
https://leetcode.cn/problems/same-tree/submissions/
分析:根节点与根节点比较,左子树与左子树比较,右子树与右子树比较
//比较两个二叉树是否相同
bool isSameTree(struct BTNode* p, struct BTNode* q){
//第一种情况:两个二叉树都为空
if (p == NULL && q == NULL) {
return true;
}
//第二种情况:一个二叉树为空且另一个不为空
//又因为代码若运行到此处至少有一个二叉树不为空
//则两个二叉树中至少有一个为空,返回错误
if (p == NULL || q == NULL) {
return false;
}
//对数据进行比较
if (p->data != q->data) {
return false;
}
//若代码运行到此处,则表示两个二叉树某一个根的节点值相同
//此时,通过递归调用先对左子树进行比较,再对右子树进行比较
//若左子树和右子树均返回true,则两个二叉树相同
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
【小总结】比较习题一和习题二,我们可以发现,两道习题在对于数值进行比较时,习题一是比较两个数值相同,习题二是比较两个数值不同。
这是为什么呢?
因为对于习题一,如果代码运行到数值比较结束处,表示当前节点数值与需要查找的数值不相同,因此需要对于左右子树使用递归调用进行查找。
对于习题二,如果码运行到数值比较结束处,表示两个二叉树当前节点的数值相同,因此需要对左右子树使用递归调用进行进一步的查找,因为某一个节点值的相同并不能代表两个二叉树是相同的。
所以,进行数值比较时,我们需要根据题目本身的要求比较。
https://leetcode-cn.com/problems/binary-tree-preorder-traversal
//计算出树的节点的个数,便于开辟内存
int TreeSize(struct TreeNode* root){
return root==NULL? 0:
TreeSize(root->left)+TreeSize(root->right)+1;
}
//进行前序遍历
void preorder(struct TreeNode* root,int* a, int i){
if(root==NULL)
return;
//后置加加,先使用再加加
a[i++]=root->val;
preorder(root->left,a,i);
preorder(root->right,a,i);
return;
}
int* preorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize=TreeSize(root);
int* a=(int*)malloc(*returnSize*sizeof(int));
preorder(root,a,0);
return a;
}
通过画图 ,检查错误:
注意!对于每一次递归而言,i是一个局部变量,栈帧中保存的i值并不相同。
因此,我们使用传址的方式对上述代码加以改进。
//计算出树的节点的个数,便于开辟内存
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);
preorder(root->right,a,pi);
return;
}
int* preorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize=TreeSize(root);
int* a=(int*)malloc(*returnSize*sizeof(int));
int i=0;
preorder(root,a,&i);
return a;
}
572. 另一棵树的子树 - 力扣(Leetcode)
思路:让左边树的每一棵子树都与右边的树进行比较
//比较两个二叉树是否相同
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);
}
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);
}
二叉树遍历_牛客题霸_牛客网 (nowcoder.com)
先对示例通过前序遍历对二叉树进行图形还原
#include
#include
struct TreeNode {
struct TreeNode* left;
struct TreeNode* right;
char val;
};
//通过前序创建二叉树!
struct TreeNode* CreateTreeNode(char* a, int* pi) {
if (a[*pi] == '#') {
(*pi)++;
return NULL;
}
//开始开辟动态内存
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
//将树的节点保存的值存放到数组中
root->val = a[(*pi)++];
//开始递归
root->left = CreateTreeNode( a, pi);
root->right = CreateTreeNode( a, pi);
return root;
}
void InOrder(struct TreeNode* root){
if(root==NULL)
return ;
else
{ InOrder(root->left);
printf("%c ",root->val);
InOrder(root->right);}
}
int main() {
char a[1000];
int i = 0;
scanf("%s", a);
struct TreeNode* root = CreateTreeNode(a, &i);
InOrder(root);
return 0;
}