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

对任意一颗二叉树,如果度为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.pswp.cn/web/93772.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93772.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93772.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ高级特性——TTL、死信队列、延迟队列、事务、消息分发

目录 一、TTL 1.1设置消息的TTL 1.2设置队列的TTL 1.3两者之间的区别 二、死信队列 2.1死信的概念 2.2死信产生的条件&#xff1a; 2.3死信队列的实现 死信队列的工作原理 2.4常⻅⾯试题 三、延迟队列 3.1概念 3.2应用场景 3.3RabbitMQ 实现延迟队列的核心原理 1…

神经网络设计中关于BN归一化(Normalization)的讨论

在神经网络的结构中&#xff0c;我们常常可以看见归一化&#xff08;Normalization&#xff09;如BN的出现&#xff0c;无论是模型的backbone或者是neck的设计都与它有着重大的关系。 因此引发了我对它的思考&#xff0c;接下来我将从 是什么&#xff08;知识领域&#xff0c;诞…

MacOS 安全机制与“文件已损坏”排查完整指南

1. 背景说明macOS 为了保护系统安全&#xff0c;内置了多个安全机制&#xff1a;机制作用是否影响第三方 AppSIP (System Integrity Protection)保护系统关键文件/目录不被篡改高风险 App/驱动可能受限Gatekeeper限制未签名/未认证 App 运行阻止“未知开发者” App文件隔离属性…

package.json文件中的devDependencies和dependencies对象有什么区别?

前端项目的package.json文件中&#xff0c;dependencies和devDependencies对象都用于指定项目所依赖的软件包&#xff0c;但它们在项目的开发和生产环境中的使用有所不同。1.dependencies&#xff1a;dependencies是指定项目在生产环境中运行所需要的依赖项。这些依赖项通常包括…

【最新版】CRMEB Pro版v3.4系统源码全开源+PC端+uniapp前端+搭建教程

一.系统介绍 crmebPro版 v3.4正式发布&#xff0c;智能任务推送、动态标签管理、商城AI生产力&#xff0c;焕然一新&#xff0c;不负期待&#xff01;页面DIY设计功能全面升级&#xff0c;组件更丰富&#xff0c;样式设计更全面&#xff1b;移动端商家管理&#xff0c;让商城管…

AI 浪潮下 IT 从业者的职业展望:替代之惑与转型之道

一、引言1.1 科技变革的浪潮&#xff1a;AI 崛起与 IT 行业震荡在当今科技飞速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;无疑是最具影响力的变革力量之一。从实验室的前沿研究到广泛的商业应用&#xff0c;AI 以惊人的速度渗透到各个领域&#xff0c;彻底改变…

DSP音频算法移植优化工程师实战

以下以音频FIR滤波器算法为例&#xff0c;完整演示从MATLAB原型 → Python验证 → TI DSP C语言移植优化的全流程&#xff0c;包含关键代码和优化技巧&#xff1a;关键优化技术解析&#xff1a; 内存访问优化使用#pragma DATA_ALIGN确保64位对齐&#xff08;满足LDDW指令要求&a…

Spark 运行流程核心组件(三)任务执行

一、启动模式 1、standalone资源申请&#xff1a;Driver向Master申请Executor资源Executor启动&#xff1a;Master调度Worker启动Executor注册通信&#xff1a;Executor直接向Driver注册 2、YARNDriver向YARN ResourceManager(RM)申请AM容器RM分配NodeManager(NM)启动AM&#x…

rabbitmq发送的延迟消息时间过长就立即消费了

RabbitMQ延迟消息在设置过长时间后被立即消费的问题&#xff0c;通常与以下原因有关&#xff1a; TTL限制问题 RabbitMQ对消息TTL(Time To Live)有32位整数限制(0-4294967295毫秒)&#xff0c;约49.7天。超过该值的延迟时间会导致消息立即被消费解决方案&#xff1a;确保设置的…

kafka的pull的依据

1. 每次 pull() 是否必须在提交上一批消息的 offset 之后&#xff1f;绝对不需要&#xff01; 提交 offset 和调用 poll() (拉取消息) 是两个完全独立的行为。消费者可以连续调用 poll() 多次&#xff0c;期间完全不提交任何 offset。 这是 Kafka 消费者的正常工作模式。提交 o…

学习嵌入式的第二十一天——数据结构——链表

单向链表特点&#xff1a;存储的内存空间不连续 。为了弥补顺序存储存劣势。优势 插入&#xff0c;删除 O(1) 动态存储 &#xff0c;在程序运行期间决定大小。劣势&#xff1a; 不能随机访问 O(N) 节点-> 数据域指针域 顺序表(数组) 只有数据域链表的操作代码&#xff1…

Rust Web 全栈开发(十三):发布

Rust Web 全栈开发&#xff08;十三&#xff09;&#xff1a;发布Rust Web 全栈开发&#xff08;十三&#xff09;&#xff1a;发布发布 teacher_service发布 svr测试 teacher_service 和 svr发布 wasm-client测试 wasm-clientRust Web 全栈开发&#xff08;十三&#xff09;&a…

Zephyr 中的 bt_le_per_adv_set_data 函数的介绍和应用方法

目录 概述 1 函数接口介绍 1.1 函数原型 1.2 功能详解 2 使用方法 2.1 创建流程 2.1.1 创建扩展广播实例 2.1.2 设置周期性广播数据 2.1.3 配置周期性广播参数 2.1.4 启动广播 2.2 主流程函数 2.3 关键配置 (prj.conf) 3 高级用法 3.1 大数据分片传输 3.2 动态数…

Ansible 角色管理指南

Ansible 角色管理指南 实验环境设置 以下命令用于准备实验环境&#xff0c;创建一个工作目录并配置基本的Ansible设置&#xff1a; # 创建web工作目录并进入 [azurewhiskycontroller ~]$ mkdir web && cd web# 创建Ansible配置文件 [azurewhiskycontroller web]$ cat &…

【补充】数据库中有关系统编码和校验规则的简述

一、字符集和校验规则&#xfeff;1.创建数据库案例数据库创建方法&#xff1a;使用CREATE DATABASE语句创建数据库字符集指定方式&#xff1a;通过CHARACTER SETutf8指定数据库编码格式默认配置说明&#xff1a;未指定字符集时默认使用utf8和utf8_general_ci配置文件位置&…

计算机网络 HTTP1.1、HTTP2、HTTP3 的核心对比及性能分析

以下是 HTTP/1.1、HTTP/2、HTTP/3 的核心对比及性能分析&#xff0c;重点关注 HTTP/3 的性能优势&#xff1a;&#x1f4ca; HTTP 协议演进对比表特性HTTP/1.1 (1997)HTTP/2 (2015)HTTP/3 (2022)传输层协议TCPTCPQUIC (基于 UDP)连接建立TCP 三次握手 TLS 握手 (高延迟)同 HTT…

【计算机视觉与深度学习实战】07基于Hough变换的答题卡识别技术:原理、实现与生物识别拓展(有完整代码)

1. 引言 在人工智能和计算机视觉快速发展的今天,自动化图像识别技术已经渗透到社会生活的各个角落。从工业质检到医学影像分析,从自动驾驶到教育评估,计算机视觉技术正在重塑我们与数字世界的交互方式。在这众多应用中,答题卡识别技术作为教育信息化的重要组成部分,承载着…

《WASM驱动本地PDF与Excel预览组件的深度实践》

WASM为何能成为本地文件解析的核心载体,首先需要跳出“前端只能处理轻量任务”的固有认知,从“性能与兼容性平衡”的角度切入。PDF与Excel这类文件格式的解析,本质是对复杂二进制数据的解码与重构——PDF包含嵌套的对象结构、字体渲染规则和矢量图形描述,Excel则涉及单元格…

Oracle Free 实例重装系统操作指南

之前申请了两台 x86 架构的 Oracle 机器&#xff0c;偶尔用来部署开源项目测试&#xff0c;有一台在测试 SSH 相关功能时 “变砖”&#xff0c;网上看重装系统发现很繁琐就没去打理&#xff0c;近期又想到这个机器&#xff0c;发现去年就有了官方重装方法&#xff0c;简单配置下…

Linux 基础指令与权限管理

一、Linux 操作系统概述1.1 操作系统的核心价值操作系统的本质是 "使计算机更好用"。它作为用户与硬件之间的中间层&#xff0c;负责内存管理、进程调度、文件系统管理和设备驱动管理等核心功能&#xff0c;让用户无需直接操作硬件即可完成复杂任务。在服务器领域&am…