当前位置: 首页 > news >正文

数据结构:二叉树oj练习

在讲今天的题目之前,我们还需要讲一下二叉树的以下特点:

对任意一颗二叉树,如果度为0的节点个数是n0,度为2的节点个数是n2,则有n0=n2+1.

证明:二叉树总的节点个数是n,那么有n=n0+n1+n2

           二叉树的度为n-1=n1*1+n2*2

结合上面两个式子,就有:n0=n2+1

完全二叉树中,度为1的结点数只有0或1两种可能

说明:因为完全二叉树的结点是连续编号的,最后一层的结点要么是满的,要么缺少右边的若干结点,所以度为1的结点最多有1个。

选择题

题目1

某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( )
A 不存在这样的二叉树
B 200
C 198
D 199

解释:叶子结点的个数等于度为2的节点的个数+1,所以结果是200

题目2

在具有 2n 个结点的完全二叉树中,叶子结点个数为( )
A n
B n + 1
C n - 1
D n / 2

度为2的节点个数=度为0的节点个数-1,即n2=n0-1

由于是完全二叉树,度为1的节点个数只有0或1两种可能。

如果度为1的节点个数为1,那么1+n0+n0-1=2n,就能得到n0=n,即A可选

如果度为1的节点个数为0,那么n0+n0-1=2n,就会得到n0=(2n+1)/ 2,这是一个小数,所以不合理。

综上,这道题的答案选A。

题目 3

一棵完全二叉树的结点数为 531 个,那么这棵树的高度为( )
A 11
B 10
C 8
D 12

我们知道,二叉树第k层节点个数为2^(k-1),前k层节点个数为2^(k)-1

假设完全二叉树的高度为h,那么完全二叉树节点个数的范围是: 2^(h-1)再到2^(h)-1.

这个范围是咋来的呢?首先第一个范围,既然一共有h层,那么根据公式,前h-1层就一共有2^(h-1)-1个节点,而第h层最少有1各节点,所以前h层应该至少是有2^(h-1)个节点。当这个树为满二叉树时,节点个数达到最大,前h层节点个数一共是:2^(h)-1。

结合这个范围,我们就可以求得答案是10,即选B

题目 4

一个具有 767 个结点的完全二叉树,其叶子结点个数为( )
A 383
B 384
C 385
D 386

假设节点个数是n,那么结合结论,n=2*n0-1+n1,我们知道,完全二叉树的节点个数要么是0,要么是1,带入公式中我们可以得到,n0=384,此时n1=0

题目 5

二叉树的先序遍历和中序遍历如下:前序遍历:EFHIGJK;中序遍历:HFIEJKG。则二叉树后续遍历序列:()

如果我们知道前序遍历+中序遍历  或者  中序遍历+后序遍历,就可以推导出二叉树的结构。

题目 6

设一棵二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为____。 A. adbce

B. decab

C. debac

D. abcde

编程题

144. 二叉树的前序遍历 - 力扣(LeetCode)

这道题就是简单的前序遍历,我们之前在二叉树的实现方法中已经写过了,只需要将代码稍加修改就可以咯:

 void preorder(struct TreeNode* root,int*res, int* returnSize){if(root==NULL){return ;}//先存根节点res[(*returnSize)++]=root->val;preorder(root->left,res,returnSize);preorder(root->right,res,returnSize);}
int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{*returnSize=0;//树中节点的数目在100内int*res=(int*)malloc(sizeof(int)*100);//前序遍历preorder(root,res,returnSize);return res;
}

145. 二叉树的后序遍历 - 力扣(LeetCode)

void postorder(struct TreeNode* root, int* res, int* returnSize)
{if (root == NULL){return;}postorder(root->left, res, returnSize);postorder(root->right, res, returnSize);res[(*returnSize)++] = root->val;
}int* postorderTraversal(struct TreeNode* root, int* returnSize) {*returnSize = 0;//树中节点的数目在100内int* res = (int*)malloc(sizeof(int) * 100);//后序遍历postorder(root, res, returnSize);return res;
}

94. 二叉树的中序遍历 - 力扣(LeetCode)

 void inorder(struct TreeNode* root, int* res, int* returnSize)
{if (root == NULL){return;}inorder(root->left, res, returnSize);res[(*returnSize)++] = root->val;inorder(root->right, res, returnSize);}int* inorderTraversal(struct TreeNode* root, int* returnSize) {*returnSize = 0;//树中节点的数目在100内int* res = (int*)malloc(sizeof(int) * 100);//中序遍历inorder(root, res, returnSize);return res;}

965. 单值二叉树 - 力扣(LeetCode)

这一道题的简单思路也是递归,如果一棵树是单值树,那么他的子树也是单值树,那我们就可以把大问题拆分成若干个子问题了:

bool isUnivalTree(struct TreeNode* root) 
{if(root==NULL){return true;}if(root->left){if(root->left->val!=root->val){return false;}}if(root->right){if(root->right->val!=root->val){return false;}}return  isUnivalTree(root->left) &&  isUnivalTree(root->right);
}

我们可以模拟一下递归过程:

100. 相同的树 - 力扣(LeetCode)

这道题的思路也是利用递归,如果两颗树的根节点相同,那就只需要再比较两颗树的左右子树是否相同即可:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{if(p==NULL&&q==NULL){return true;}if(p==NULL){return false;}if(q==NULL){return false;}if(p->val!=q->val){return false;}//表示根节点不为空且指向的值相等return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

我们可以模拟一下递归过程:

101. 对称二叉树 - 力扣(LeetCode)

如图,判断一个树是否是对称二叉树,就是要比较根节点的左右子树,我们可以把根节点的左右子树看成两棵独立的二叉树,问题就转换为比较这两棵树是否对称。

两棵树是否互为对称树,就是比较树A上某个节点的左孩子节点的值与树B上对应节点的右孩子节点的值以及树A上某个节点的右孩子节点的值与树B上对应节点的左孩子节点的值是否相等,如果相等的话,就继续递归比较孩子节点的值。

 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;}//两棵树根节点相同,再比较树A的左孩子与树B的右孩子是否相同,以及树A的右孩子与树B的左孩子是否相同return isSameTree(p->left,q->right)&&isSameTree(p->right,q->left);}
bool isSymmetric(struct TreeNode* root)
{return  isSameTree(root->left,root->right);
}

模拟递归过程:

572. 另一棵树的子树 - 力扣(LeetCode)

这一体的思路比较好想,我们可以先比较subroot是否与整棵树相同,如果相同,那就可以直接返回了,如果不相同,说明subroot可能是树的子树,就需要遍历整棵树的节点,看是否存在以某一个节点为根的树与subroot相同:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{if(p==NULL&&q==NULL){return true;}if(p==NULL){return false;}if(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(subRoot==NULL){return true;}if(root==NULL){return false;}if(isSameTree(root,subRoot)){return true;}return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}

二叉树遍历_牛客题霸_牛客网

我们之前说过,如果知道前序遍历+中序遍历  或者  中序遍历+后序遍历,就可以推导出二叉树的结构。但是现在题目中只给了我们前序遍历的结果,我们还能根据这个去构建二叉树的结构吗?

在这一题中是可以的,因为题中给我们的字符串是带有'#'的,这表示空指针,前序遍历的顺序是按照根节点->左子树->右子树,当我们遇到‘#’的时候,就无法继续往下遍历,而是要回到原来子树的根,这没说这可能有点抽象,我们利用题目中给的测试样例来手动还原二叉树的结构:

利用遍历结果构建二叉树听起来好像挺难的,但其实就是对二叉树进行遍历,我们在写前序遍历的代码的时候,将访问二叉树的节点的操作写成了打印二叉树的节点值,在这里,无非就是让我们在前序遍历过程中将访问二叉树的节点的操作写成了创建节点呀,具体思路还是没有变呀,那我们就继续写一下代码吧:

//二叉树的构建与遍历
#include<stdio.h>
#include<stdlib.h>
//二叉树的节点的定义
typedef struct btnode {char data;struct btnode* left;struct btnode* right;
} btnode;btnode* buynode(char x) {btnode* newnode = (btnode*)malloc(sizeof(btnode));newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}//最后返回根节点
//pi表示指向的字符在字符数组中的下标,由于形参的改变需要影响实参,所以我们这里采用传址调用
btnode* precreattree(char* ch, int* pi) {if (ch[*pi] == '#') {(*pi)++;return NULL;}//先创建根节点btnode* root = buynode(ch[(*pi)++]);//再创建左子树root->left = precreattree(ch, pi);//创建右子树root->right = precreattree(ch, pi);//返回根节点return root;
}
//中序遍历树的节点
void inorder(btnode* root) {if (root == NULL) {return;}//先遍历左子树inorder(root->left);//再访问根节点printf("%c ", root->data);//再遍历右子树inorder(root->right);
}
int main() {char ch[100];//输入字符串scanf("%s", ch);//输入的字符串是二叉树前序遍历的结果,我们需要根据这个结果去创建二叉树int i = 0;btnode* root = precreattree(ch, &i);//中序遍历inorder(root);return 0;
}

今天的内容还是比较丰富的,这些算法题也是比较经典的,能看到这里的兄弟们我真的觉得你们很棒,大家在自己的电脑上也要好好把代码敲一下,把图画一下,把思路整理一下哦!!

http://www.dtcms.com/a/340131.html

相关文章:

  • 实现进度条
  • 【大模型早期融合的非标记化架构】
  • 学习strandsagents的http_request tool
  • 【上升跟庄买入】副图/选股指标,动态黄色线由下向上穿越绿色基准线时,发出买入信号
  • Ubuntu 20 各种网卡配置IP的方法
  • 【PyTorch】多对象分割项目
  • 别再手动处理字符串!Python 正则表达式实战手册(入门到精通)
  • 【深度学习新浪潮】Meta 开源最新视觉大模型 DINOv3,该模型有哪些技术亮点?
  • 【数据结构】使用队列解决二叉树问题
  • CentOS安装SNMPWalk
  • C++高频知识点(二十二)
  • 算法题Day3
  • 理解MCP:开发者的新利器
  • 从零开始理解一个复杂的 C++/CUDA 项目 Makefile
  • React学习(六)
  • 梅森公式计算传递函数及结构图转换为信号流图过程
  • STM32-FreeRTOS快速入门指南(中)
  • HJ3 明明的随机数
  • 数据结构——双链表
  • 人工智能细分方向全景图:从入门到专精的技术路径
  • AI出题人给出的Java后端面经(十⑨)(日更)
  • 零成本上线个人网站 | Cloudflare Pages 全流程实战指南
  • A股大盘数据-20250819 分析
  • redis基础----通用命令
  • 脑电分析——ICA原理、ICALabel成分与伪迹之间一对多的关系
  • 从合规到主动免疫:大模型内容风控的创新与实践
  • 【PyTorch】单对象分割项目
  • Seata笔记
  • Day22 顺序表与链表的实现及应用(含字典功能与操作对比)
  • 不同语言的并发模型对比:Go、Java与Python