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

数据结构:二叉树的实现

目录

二叉树的遍历方式

  前序遍历:

  中序遍历:

  后序遍历:

二叉树的基本结构和功能

  基本结构:

  基本功能:

二叉树功能的实现思路

二叉树功能的实现

   1、构建一个二叉树

   2、二叉树的销毁

   3、计算二叉树里的节点个数

   4、得到二叉树的子叶节点个数

    5、得到二叉树第K层节点个数

     6、查找二叉树值为X的节点

   7、二叉树的前/中/后序遍历

        前序遍历

        中序遍历

        后序遍历

   8、层序遍历

   9、判断二叉树是否为完全二叉树


二叉树的遍历方式

        二叉树有三种遍历方式,不同的遍历方式有不同的效果和作用。(实现二叉树的代码)

  前序遍历:

        根->左子树->右子树。

        (如上图所示)用前序遍历这个二叉树的结果是: 1 2 4 8 5 3 6 9 7

        如果加上空的子树,结果是:1 2 4 N 8 N N 5 N N 3 6 9 N N N 7 N N(为了方便理解,同一种颜色的是根的子树)


  中序遍历:

        左子树->根->右子树。

        (如上图所示)用前序遍历这个二叉树的结果是: 4 8 2 5 1 9 6 3 7

        如果加上空的子树,结果是:N 4 N 8 N 2 N 5 N 1 N 9 N 6 N 3 N 7 N(为了方便理解,同一种颜色的是根的子树) 


  后序遍历:

        左子树->右子树->根。

        (如上图所示)用前序遍历这个二叉树的结果是: 8 4 5 2 9 6 7 3 1

        如果加上空的子树,结果是:N N N 8 4 N N 5 2 N N 9 6 N N 7 3 1(为了方便理解,同一种颜色的是根的子树) 


二叉树的基本结构和功能

  基本结构:

        我们知道二叉树里有一个值和指向两个子树的指针构成,所以我们可以用下面的结构体来作为一个节点。

typedef char BTDataType;//为了便于以后因不同需求而更改。
//节点
typedef struct BinaryTreeNode
{BTDataType _data;//存放值struct BinaryTreeNode* _left;//一个指向左子树的指针struct BinaryTreeNode* _right;//一个指向右子树的指针
}BTNode;

  基本功能:

  1. 通过一个关于二叉树遍历的字符串来构建出一个二叉树
  2. 二叉树的销毁
  3. 得到二叉树的节点个数
  4. 得到二叉树的子叶节点个数
  5. 得到二叉树第K层节点个数
  6. 查找二叉树值为X的节点
  7. 二叉树的前序遍历
  8. 二叉树的中序遍历
  9. 二叉树的后序遍历
  10. 层序遍历
  11. 判断二叉树是否为完全二叉树

二叉树功能的实现思路

        (二叉树的大部分功能的实现都需要用到递归,所以我们要对递归一定熟练度)当我们要构建一个二叉树的时候,可以用递归的方式来连接一个一个的节点。其他的功能最主要的也是用递归

实现的。


二叉树功能的实现

   1、构建一个二叉树

        当我们要构建一个二叉树,我们首先要确定它的构建方式——前序、中序还是后序。(这里以前序遍历为例)

        前序遍历的方式是根->左子树->右子树

        若我们要通过前序遍历的数组" A B D # # E # H # # C F # # G # # "构建二叉树,我们首先可以先画出构建好的二叉树的图形(如下图所示),这回让你对你要创建的二叉树有更深的理解。

         利用递归的性质,我们只要遇到 ' # '就返回,反之,就创建节点,然后使其链接左子树和右子树。

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{//当遇到' # '就返回if (a[*pi] == '#'){(*pi)++;return NULL;}//创建一个节点BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("malloc fail");return NULL;}root->_data = a[*pi];(*pi)++;root->_left = BinaryTreeCreate(a, pi);//链接左子树root->_right = BinaryTreeCreate(a, pi);//链接右子树//最后返回根return root;
}

        如果我们想要用其他的遍历方式来构建二叉树可以调整一下链接左子树的时机。(记得字符串里的内容要是对应的遍历方式)


   2、二叉树的销毁

        要销毁一个二叉树,我们首先要确定销毁方式,因二叉树的结构只能用后序遍历(左子树->右子树->根)的方式来销毁二叉树。

        假如我们用前序(左子树->根->右子)或中序(左子树->根->右子树)的方式销毁二叉树,我们都会先销毁根,导致我们找不到后续的子树,所以我们只能用后序的方式来销毁二叉树。

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return;}//先遍历到子叶再开始销毁BinaryTreeDestory(&(*root)->_left);BinaryTreeDestory(&(*root)->_right);free(*root);*root = NULL;
}

   3、计算二叉树里的节点个数

        计算节点个数,我们只需要遇到空指针就返回,反之就加左子树和右子树之和再加1(本身)即可。

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;
}

   4、得到二叉树的子叶节点个数

        遇到空就返回0,如果本身非空且有左子树则加1,如果本身非空且有右子树则加1,这样我们就可以得到二叉树的子叶节点个数了。

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root && root->_left == NULL)return 1;if (root && root->_right == NULL)return 1;return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}


    5、得到二叉树第K层节点个数

        我们先设根节点为第一层,则第二层就为k-1层,然后推导,当k == 1的时候就是我们需要计算节点个数的层数。若该二叉树没有第k层呢?我们只需当k == 0时就返回0即可。

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL)return 0;//当k == 1时就返回1if (k == 1)return 1;return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}

     6、查找二叉树值为X的节点

        在二叉树里查找一个值的时候,我们首先要确定查找方式,(这里以前序为例),我们用前序查找,如果左子树有这个值就返回该节点,没有就返回NULL,然后再查找右子树,若也没有就返回NULL。

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->_data == x)return root;BTNode* left = BinaryTreeFind(root->_left, x);return left != NULL ? left : BinaryTreeFind(root->_right, x);
}

        如果不在左子树,那就只有两种可能,一个是在右子树,一个是没有这个值。这里的left都为空的话,那只能去右子树里去找了。


   7、二叉树的前/中/后序遍历

        这三种遍历方式在二叉树的实现都差不多,只是要区分先后顺序。

        前序遍历

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){	printf("# ");return;}printf("%c ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);
}

        中序遍历

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("# ");return;}BinaryTreePrevOrder(root->_left);printf("%c ", root->_data);BinaryTreePrevOrder(root->_right);
}

        后序遍历

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("# ");return;}BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);printf("%c ", root->_data);
}

   8、层序遍历

        层序遍历就与上面的遍历有所不同,这里我们要利用队列来存储节点的指针来达到层序遍历。

        这里的层序遍历的结构是:A B C D E F G H 

        首先,我们要清楚队列的性质,队列是由链表构成,先进先出的方式来进出队列。开始先入一个根节点,每当出一个二叉树的节点就得要入它的左子树节点和右子树节点。遇到不是空节点就入队列。这样我们就可以实现二叉树的层序遍历。(这里避免过于臃肿就不写队列的过程了,如果想了解一下队列可以看看这篇文章详解栈和队列的实现以及它们的相互实现)

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if(root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);printf("%c", front->_data);if(front->_left)QueuePush(&q, front->_left);if (front->_right)QueuePush(&q, front->_right);QueuePop(&q);}printf("\n");
}

   9、判断二叉树是否为完全二叉树

        判断二叉树是否为完全二叉树的实现,跟上面基本同理,当与到空的时候就直接break去判断后面还有没有其他的数,无,则是完全二叉树,反之,不是完全二叉树。

        原理:(将空指针视为 N )如果一个二叉树是完全二叉树,将像上面入队列的时候,队列中存储的数据到N的时候后面就只有N了。但如果还有其他的数,那就不可能是完全二叉树。

// 判断二叉树是否是完全二叉树
bool BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if(root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if( front == NULL)break;if(front->_left)QueuePush(&q, front->_left);if (front->_right)QueuePush(&q, front->_right);}while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if( front){QueueDistory(&q);return false;}}   return true;
}

(完)
        

相关文章:

数据结构:二叉树的实现

目录 二叉树的遍历方式 前序遍历: 中序遍历: 后序遍历: 二叉树的基本结构和功能 基本结构: 基本功能: 二叉树功能的实现思路 二叉树功能的实现 1、构建一个二叉树 2、二叉树的销毁 3、计算二叉树里的节点个数 4、得…...

Helm离线部署Rancher2.7.10

环境依赖: K8s集群、helm 工具 Rancher组件架构 Rancher Server 包括用于管理整个 Rancher 部署的所有软件组件。 下图展示了 Rancher 2.x 的上层架构。下图中,Rancher Server 管理两个下游 Kubernetes 集群 准备Rancher镜像推送到私有仓库 cat >…...

Linux目录的作用和常用指令

目录结构及其详细作用 / (根目录) Linux文件系统的起点,所有文件和目录都在其下。 /bin 存放系统启动和运行时所需的基本命令,如 ls, cp, mv, rm,这些命令在单用户模式下或系统崩溃时仍然可用。 /boot 包含启动引导加载器的文件和Linux内核…...

Nvidia/算能 +FPGA+AI大算力边缘计算盒子:隧道和矿井绘图设备

RockMass 正在努力打入采矿业和隧道工程利基市场。 这家位于多伦多的初创公司正在利用 NVIDIA AI 开发一款绘图平台,帮助工程师评估矿井和施工中的隧道稳定性。 目前,作为安全预防措施,地质学家和工程师会站在离岩石五米远的地方&#xff0…...

MySQL物理备份

目录 备份策略 全量备份 (Full Backup) 增量备份 (Incremental Backup) 差异备份 (Differential Backup) 使用 Percona XtraBackup 全量备份 步骤 1:全量备份 步骤 2:备份后处理(应用日志) 步骤 3:恢复备份 验…...

AWT常用组件

AWT中常用组件 前言一、基本组件组件名标签(Label类)Label类的构造方法注意要点 按钮(Button)Button的构造方法注意要点 文本框(TextField)TextField类的构造方法注意要点 文本域(TextArea)TextArea 的构造方法参数scrollbars的静态常量值 复选框&#x…...

CorelDRAW2024破解激活码序列号一步到位

亲们,今天给大家种草一个神奇的软件——CorelDRAW破解2024最新版!🎨这是一款专业级的矢量图形设计软件,无论你是平面设计师、插画师还是设计师,都能在这个软件中找到你需要的工具和功能。✨ 让我来给大家介绍一下这款软…...

Webpack前端打包工具详解

目录 Webpack前端打包工具详解一、Webpack 的作用二、Webpack 的安装和基本使用1. 安装 Webpack2. 创建 Webpack 配置文件3. 运行 Webpack 三、Webpack 核心概念1. 入口(Entry)2. 输出(Output)3. 加载器(Loaders&#…...

计网总结☞网络层

.................................................. 思维导图 ........................................................... 【Wan口和Lan口】 WAN口(Wide Area Network port): 1)用于连接外部网络,如互联…...

【全开源】云调查考试问卷系统(FastAdmin+ThinkPHP+Uniapp)

便捷、高效的在线调研与考试新选择​ 云调查考试问卷是一款基于FastAdminThinkPHPUniapp开发的问卷调查考试软件,可以自由让每一个用户自由发起调查问卷、考试问卷。发布的问卷允许控制问卷的搜集、回答等各个环节的设置,同时支持系统模板问卷&#xff…...

网络安全难学吗?2024该怎么系统学习网络安全?

学习网络安全需要循序渐进,由浅入深。很多人对网络安全进行了解以后,就打算开始学习网络安全,但是又不知道怎么去系统的学习。 网络安全本身的知识不难,但需要学习的内容有很多,其中包括Linux、数据库、渗透测试、等保…...

2 程序的灵魂—算法-2.4 怎样表示一个算法-2.4.6 用计算机语言表示算法

我们的任务是用计算机解题&#xff0c;就是用计算机实现算法&#xff1b; 用计算机语言表示算法必须严格遵循所用语言的语法规则。 【例 2.20】求 12345 用 C 语言表示。 main() {int i,t; t1; i2; while(i<5) {tt*i; ii1; } printf(“%d”,t); } 【例 2.21】求级数的…...

重生之我要精通JAVA--第八周笔记

文章目录 多线程线程的状态线程池自定义线程池最大并行数多线程小练习 网络编程BS架构优缺点CS架构优缺点三要素IP特殊IP常用的CMD命令 InetAddress类端口号协议UDP协议&#xff08;重点&#xff09;UDP三种通信方式 TCP协议&#xff08;重点&#xff09;三次握手四次挥手 反射…...

51单片机独立按键控制LED灯,按键按一次亮,再按一次灭

1、功能描述 独立按键控制LED灯&#xff0c;按键按一次亮&#xff0c;再按一次灭 2、实验原理 轻触按键:相当于是一种电子开关&#xff0c;按下时开关接通&#xff0c;松开时开关断开&#xff0c;实现原理是通过轻触按键内部的金属弹片受力弹动米实现接通和断开&#xff1b;…...

【上海大学计算机组成原理实验报告】七、程序转移机制

一、实验目的 学习实现程序转移的硬件机制。 掌握堆栈寄存器的使用。 二、实验原理 根据实验指导书的相关内容&#xff0c;实验箱系统的程序转移硬件机制在于&#xff0c;当LDPC有效时&#xff0c;如果此时DUBS上的值就是转移的目标地址&#xff0c;则此目标地址被打入PC&am…...

LLVM Cpu0 新后端7 第一部分 DAG调试 dot文件 Machine Pass

想好好熟悉一下llvm开发一个新后端都要干什么&#xff0c;于是参考了老师的系列文章&#xff1a; LLVM 后端实践笔记 代码在这里&#xff08;还没来得及准备&#xff0c;先用网盘暂存一下&#xff09;&#xff1a; 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…...

修复www服务trace漏洞

验证方式&#xff1a;curl -v -X TRACE ip:port&#xff0c;或使用其他接口调试工具如Postman 响应&#xff1a;状态行405 Method Not Allowed且响应体无内容 方案一&#xff1a;使用过滤器 若webserver是tomcat, 添加过滤器的方式有很多 Component public class TraceHttpMe…...

算法:101. 对称二叉树

对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; 树中节…...

wordpress 使用api发布文章

1.安装插件 在/wp-content/plugins/目录执行以下命令 $ sudo git clone https://github.com/WP-API/Basic-Auth.git 2.Python脚本 import requestsurl http://www.ziyuanwang.online/wp-json/wp/v2/postsuser adminpassword xxxxxheaders {Content-Type: application/j…...

《Brave New Words 》2.2 阅读理解的未来,让文字生动起来!

Part II: Giving Voice to the Social Sciences 第二部分&#xff1a;为社会科学发声 The Future of Reading Comprehension, Where Literature Comes Alive! 阅读理解的未来&#xff0c;让文字生动起来&#xff01; Saanvi, a ninth grader in India who attends Khan World S…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...