数据结构——lesson8二叉树的实现

💞💞 前言

hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹
在这里插入图片描述

💥个人主页:大耳朵土土垚的博客
💥 所属专栏:数据结构学习笔记
💥对于数据结构顺序表、链表、堆有疑问的都可以在上面数据结构的专栏进行学习哦~ 有问题可以写在评论区或者私信我哦~

前面我们学习过二叉树的前、中、后序遍历 以及二叉树层序遍历,今天我们将继续学习有关二叉树的实现🥳🥳🥳

1.二叉树的构建

1.1二叉树的结构

typedef char BTDataType;//这里使用字符类型方便看下面的ABC等字母
//typedef int BTDataType;其他我们使用int
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;//二叉树的结构

二叉树每个节点应该包含该节点的值,以及其左右子节点的地址

1.2创建二叉树新节点

//创建新节点
BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = x;return newnode;
}

使用malloc函数创建节点,最后销毁时要使用free来释放,malloc大小为BTNode的节点;
对于mallc函数有疑问的可以查看土土的博客——动态内存函数介绍;

1.3创建二叉树

以数组"ABD##E#H##CF##G##"为例

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{if(a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = BuyNode(a[*pi]);(*pi)++;root->left = BinaryTreeCreate(a, pi);root->right = BinaryTreeCreate(a, pi);return root;
}

利用监视进行可视化如下:
在这里插入图片描述

在这里插入图片描述
可以看到形成了逻辑结构如下图所示的二叉树:
在这里插入图片描述

我们将这里的’#'当作空的标志,用来实现二叉树的结构,并利用递归左子树右子树来构建二叉树。

2.二叉树的销毁

// 二叉树销毁
void BinaryTreeDestroy(BTNode* root)
{if (root == NULL)return;//类似于后序,先释放左右子树再释放根节点BinaryTreeDestroy(root->left);BinaryTreeDestroy(root->right);free(root);
}

这里二叉树的销毁需要对二叉树进行遍历,我们前面学习过四种二叉树的遍历——前、中、后序以及层序遍历,对于销毁二叉树来说使用后序遍历比较合适,因为先释放左右子树再释放根节点这样可以防止找不到节点。

3.二叉树节点个数

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

如果节点是空就返回,不是空就继续递归找其左子树右子树直到找到空也就是叶子节点的左右子树,此时再递归返回叶子节点的父节点时要+1,用来表示计算的叶子节点;依次类推不是NULL就+1,这样最后就是二叉树节点的个数了;图解如下:
以下图为例:
在这里插入图片描述
1.找到NULL:
在这里插入图片描述返回左右子树为空后要+1;
2.依次类推递归返回:
在这里插入图片描述
在这里插入图片描述

也可以看下面的递归展开图:
以下图为例:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

4.二叉树叶子节点个数

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

叶子节点对应其左右子树都为空,就返回1,利用递归实现

5.二叉树第k层节点个数

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{assert(k);if(root == NULL)return 0;//k层节点个数if (k == 1)return 1;return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

我们可以利用k-1依次往下递归,直到k = 1 时此时,就是第k层就返回1;

6.二叉树查找

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;//前序遍历来查找if (root->data == x){return root;}BTNode* res1 = BinaryTreeFind(root->left, x);if (res1)return res1;BTNode* res2 = BinaryTreeFind(root->right, x);if (res2)return res2;//没有找到返回空return NULL;
}

在运用递归时要返回值时记得将递归找到的值保存起来,防止找不到耗费力气重新再找。

7.二叉树高度

//求二叉树高度
int BTreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = BTreeHeight(root->left);int rightHeight = BTreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

类似于二叉树节点个数的递归,返回时每次+1,并且我们还需要将每次计算的高度与二叉树查找一样保存起来防止浪费时间再去遍历查找,此外左子树右子树高度不一致时要取较大的那一个;

8.判断是否是完全二叉树

在此之前我们先回顾一下特殊的二叉树:

1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是2^k - 1 ,则它就是满二叉树。
2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
要注意的是满二叉树是一种特殊的完全二叉树。
在这里插入图片描述

这里判断是否为完全二叉树的实现与之前讲过的二叉树层序遍历相似需要利用队列来实现,队列的实现在这——二叉树层序遍历里面包含队列代码的完整实现,这里就不过多描述,我们直接来使用。记得使用时要先写队列并包含对应的头文件哦~

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{//利用队列先进先出的特点Queue qt;QueueInit(&qt);if (root)//如果根节点非空则入队列QueuePush(&qt, root);while (!QueueEmpty(&qt))//判断队列非空{QDataType front = QueueFront(&qt);//取出队头元素QueuePop(&qt);if (front == NULL)break;//遇到空就跳出QueuePush(&qt, front->left);//再将左右子树的节点入队列QueuePush(&qt, front->right);}//break跳出后//判断之后的元素是否有非空值//有非空值则不是完全二叉树while (!QueueEmpty(&qt)){QDataType front = QueueFront(&qt);QueuePop(&qt);if (front != NULL){QueueDestroy(&qt);return false;}}//如果没有非空值返回trueQueueDestroy(&qt);return true;
}

思路:利用二叉树的层序遍历,层序遍历一遍如果有空指针NULL且队列非空时如果队列里面还有非空值那么就不是完全二叉树。

9.结语

以上就是有关二叉树实现的内容啦 ~ 关键是要理解递归是怎么实现的,利用二叉树由根节点、左右子树构成的特性来实现递归,完结撒花 ~🥳🥳🎉🎉🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2871392.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用人工智能打造超用户预期的个性化购物体验

回看我的营销职业生涯,我见证了数字时代如何重塑客户期望。从一刀切的方法过渡到创造高度个性化的购物体验已成为企业的关键。在这个客户期望不断变化的新时代,创造个性化的购物体验不再是奢侈品,而是企业的必需品。人工智能 (AI&…

UnityShader(十六)凹凸映射

前言: 纹理的一种常见应用就是凹凸映射(bump mapping)。凹凸映射目的就是用一张纹理图来修改模型表面的法线,让模型看起来更加细节,这种方法不会改变模型原本的顶点位置(也就是不会修改模型的形状&#xf…

资深老鸟经验,性能测试-性能指标分析总结,一篇策底概全...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 性能测试指标 1、…

146 Linux 网络编程2 ,Socket编程,如何创建Linux 服务器 和linux 客户端

IPport 就是一个程序在网络上的身份证号码。 这意味着我们需要如果写一个服务器,至少需要将这台服务器的ip 和 端口号写到程序里面。 实际上更细化的说:应该是将这三都写进程序里面 : IP类型(IPV4或者IPV6)&#xff…

Anaconda安装proplot库

看了一下Anaconda中的环境,现在我有4个,其中gee是一个虚拟环境 因此一般在prompt中装库时要先进入其中一个虚拟环境 conda activate geepip install proplot --no-deps下完了之后,发现版本不对应 conda install matplotlib3.4.3

面试算法-39-删除链表的倒数第 N 个结点

题目 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5] 解 class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {L…

【Linux】进程信号{初识信号/常见的信号/中断信号/信号的产生}

文章目录 0.浅谈中断信号1.初识信号2.中断信号3.信号的产生测试:SIGINT 4.core dump核心转储5.系统接口产生信号5.1kill给指定发5.2raise向自己发5.3abort自己给自己发6 6.由于软件条件不满足产生信号6.1SIGPIPE6.2SIGALRM 7. 硬件异常产生信号7.1除零错误7.2野指针…

云服务器容器常用操作系统介绍

常用操作系统介绍 开源软件国内镜像源Alpine操作系统介绍镜像源修改镜像源apk包管理器 Debian操作系统介绍镜像源修改镜像源apt包管理器 ubuntu操作系统介绍修改镜像源apt包管理器 CentOS操作系统介绍修改镜像源yum包管理器 开源软件国内镜像源 名称地址南京大学mirror.nju.ed…

奇酷网络董事长吴渔夫:AI时代的工作节奏

奇酷网络董事长吴渔夫今日分享: 1、从2024年春节后上班至今,我每天都是工作16小时的。除了睡觉时间段,其它时间都在工作;连吃个饭也是一边吃一边看手机,阅读AI新闻、学习Sora和AI知识的。 2、我的工作方式&#xff0…

22 OpenCV 直方图计算

文章目录 直方图概念split 通道分离函数calcHist 计算直方图normalize 归一化函数示例 直方图概念 上述直方图概念是基于图像像素值,其实对图像梯度、每个像素的角度、等一切图像的属性值,我们都可以建立直方图。这个才是直方图的概念真正意义&#xff0…

PHP魔术方法详解

php魔术方法是一些特殊的方法&#xff0c;由特定的环境来进行触发。 这些魔术方法让开发者能够更好地控制对象的行为&#xff0c;特别是在处理不常见的操作或者需要自动化处理某些任务时非常有用。 1、_construct()构造函数&#xff1a; <?php highlight_file(__FILE__);…

【静夜思】为什么我们会如此喜欢夜晚呢

作为一名大学生&#xff0c;熬夜对我来说已是常态。每天都是近乎一点钟才有困意&#xff0c;觉得应该上床睡觉了&#xff0c;即使明天早八&#xff0c;即使明天有很多课。我也观察过身边的朋友&#xff0c;他们中大多数也和我一样&#xff0c;基本都是在12点过后才入睡。当今的…

DDL - 建立数据库,建表代码版(Way 2)

一、DB操作 show databases; create database DBOFRYX; drop database DBOFRYX; use DBOFRYX; 二、表操作&#xff08;表和表结构、字段是A、B两姐妹&#xff09; (1) use DBOFRYX; show tables; (2) create table TABOFRYX( name varchar(50) comment "姓名"…

【SpringBoot3】整合Druid数据源和Mybatis 项目打包和运行

文章目录 一、整合Druid数据源二、整合Mybatis2.1 MyBatis整合步骤2.1 Mybatis整合实践2.1 声明式事务整合配置2.1 AOP整合配置 三、项目打包和运行命令启动和参数说明 总结web 与 springboot 打包区别JDK8的编译环境 执行17高版本jar 一、整合Druid数据源 创建模块 &#xff1…

Cloudways搭建WordPress外贸独立站完整教程

现在做个网站不比从前了&#xff0c;搭建网站非常的简单&#xff0c;主要是由于开源的CMS建站系统的崛起&#xff0c;就算不懂编程写代码的人也能搭建一个自己的网站&#xff0c;这些CMS系统提供了丰富的主题模板和插件&#xff0c;使用户可以通过简单的拖放和配置操作来建立自…

Ubuntu Desktop - Open a New Window

Ubuntu Desktop - Open a New Window 1. Open a New WindowReferences 1. Open a New Window References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:TabContent)

仅在Tabs中使用&#xff0c;对应一个切换页签的内容视图。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 支持单个子组件。 说明&#xff1a; 可内置系统组件和自定义组件&#xff0c;支…

智慧礼金:电子礼金薄,让礼薄更添智能,你确定不进来看看?

智慧礼金&#xff1a;电子礼金薄&#xff0c;让礼薄更添智能&#xff0c;你确定不进来看看&#xff1f; 一、重要声明二、相关介绍三、使用好处四、如何找到该小程序 随着科技的不断进步&#xff0c;传统的纸质礼金簿已经逐渐被电子化管理所取代。今天&#xff0c;我们要向大家…

题目:特殊的三角形(蓝桥OJ 3008)

问题描述&#xff1a; 解题思路&#xff1a; 可以先求出1~1e6每个位置是否有解&#xff0c;后计算前缀和再求出不同区间的和。&#xff08;时间复杂度小&#xff09; 进行dfs操作&#xff1a;依次组合1~1e6所有元素。并计算每一个组合的乘积&#xff0c;在该乘积位置的cnt加一。…

OLAP与数据仓库和数据湖

OLAP与数据仓库和数据湖 本文阐述了OLAP、数据仓库和数据湖方面的基础知识以及相关论文。同时记录了我如何通过ChatGPT以及类似产品&#xff08;通义千问、文心一言&#xff09;来学习知识的。通过这个过程让我对于用AI科技提升学习和工作效率有了实践经验和切身感受。 预热 …