数据结构——链式结构二叉树

news2024/9/22 11:29:53

目录

一、二叉树的链式结构

二、手动创建一棵链式二叉树

三、 二叉树的遍历

(1)前序遍历(先序遍历)

(2)中序遍历

(3)后序遍历

四、二叉树的有关函数

 (1)头文件

(2)二叉树结点总数 

(3) 二叉树叶子结点个数

(4) 二叉树第k层结点个数

(5)二叉树的高度/深度 

(6) 二叉树查找值为x的结点

(7)二叉树的销毁 

五、层序遍历

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

七、写在最后


一、二叉树的链式结构

链表来表示二叉树,其实就是用链来指示元素的逻辑关系

链表中的每个结点由3个域组成:数据域和左右指针域,其中左右指针分别用来给出该结点左孩子和右孩子所在链的结点的存储地址。

typedef int BTDatatype;
//二叉链
typedef struct BinaryTreeNode
{
    BTDatatype val;//当前结点的值域
    struct BinaryTreeNode* left;//指向当前结点的左孩子
    struct BinaryTreeNode* right;//指向当前结点的右孩子

}

二、手动创建一棵链式二叉树

 二叉树分为空树和非空二叉树,其中非空二叉树由根结点、根结点的左孩子和根结点的右孩子组成。而根结点的左右子树又是由子树结点、子树结点的左孩子和子树结点的右孩子组成的,因此二叉树的定义是递归的。

//创建新结点
BTNode* BuyNode(int val)
{
    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    if(newnode == NULL)
    {
        perror("malloc fail!");
        reutrn NULL;
    }
    newnode->val = val;
    newnode->left = newnode->right = NULL;
    return newnode;
}

//创建二叉树
BTNode* CreatTree()
{
    BTNode* n1 = BuyNode(1);
    BTNode* n2 = BuyNode(2);
    BTNode* n3 = BuyNode(3);
    BTNode* n4 = BuyNode(4);
    BTNode* n5 = BuyNode(5);
    BTNode* n6 = BuyNode(6);
    BTNode* n7 = BuyNode(7);

    n1->left = n2;
    n1->right = n4;
    n2->left = n3;
    n4->left = n5;
    n4->right = n6;
    n5->left = n7;

    return n1;

}

三、 二叉树的遍历

(1)前序遍历(先序遍历)

访问根结点的操作发生在遍历其左右子树之

访问顺序为:根结点、左子树、右子树,即:根左右

void PerOrder(BTNode* root)
{
    //若根结点为空,直接返回
    if(root == NULL)
    {
        printf("NULL");
        return;
    }
    //先打印根结点的数据
    printf("%d ",root->val);
    //遍历左孩子
    PerOrder(root->left);
    //遍历右孩子
    PerOrder(root->right);
}

 

(2)中序遍历

 访问根结点的操作发生在遍历其左右子树之(间);

访问顺序为:左子树、根结点、右子树,即:左根右

void InOrder(BTNode* root)
{
    if(root == NULL)
    {
        printf("NULL");
        return;
    }
    InOrder(root->left);
    printf("%d ",root->val);
    InOrder(root->right);
}

(3)后序遍历

访问根结点的操作发生在遍历其左右子树之

访问顺序为:左子树、右子树、根结点,即:左右根

void PostOrder(BTNode* root)
{
    if(root == NULL)
    {
        printf("NULL");
        return;
    }
    PostOrder(root->left);
    PostOrder(root->right);
    printf("%d ",root->val);
}

四、二叉树的有关函数

 (1)头文件

// ⼆叉树结点总数 
int BinaryTreeSize(BTNode* root);
 
// ⼆叉树叶⼦结点个数 
int BinaryTreeLeafSize(BTNode* root); 

// ⼆叉树第k层结点个数 
int BinaryTreeLevelKSize(BTNode* root, int k); 

//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);

// ⼆叉树查找值为x的结点 
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

// ⼆叉树的销毁
void BinaryTreeDestory(BTNode** root);

(2)二叉树结点总数 

int BinaryTreeSize(BTNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    //根结点+左子树中结点的个数+右子树中结点的个数
    return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

(3) 二叉树叶子结点个数

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);
}

(4) 二叉树第k层结点个数

int BinaryTreeLevelKSize(BTNode* root, int k)
{
    if(root == NULL)
    {
        return 0;
    }
    //第k层
    if(k == 1)
    {
        return 1;
    }
    //左子树的第k层结点数+右子树的第k层结点数
    return BinaryTreeLevelKSize(root->left, k-1) + BinaryTreeLevelKSize(root->right, k-1);
}

(5)二叉树的高度/深度 

int BinaryTreeDepth(BTNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    //分别求得左右子树的深度
    int leftDeep = BinaryTreeDepth(root->left);
    int rightDeep = BinaryTreeDepth(root->right);
    //根结点 + 左右子树的深度的最大值
    return leftDeep > rightDeep ? leftDeep + 1 : rightDeep + 1;
}

(6) 二叉树查找值为x的结点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    if(root == NULL)
    {
        return  NULL;
    }
    找到值为x的数据
    if(root->val == x)
    {
        return root;
    }
    //在左子树中找值为x的数据
    //如果在左子树找到,直接返回,无需在右子树寻找
    BTNode* leftFind = BinaryTreeFind(root->left, x);
    if(leftFind)
    {
        return leftFind;
    }

    BTNode* rightFind = BinaryTreeFind(root->right, x);
    if(rightFind)
    {
        return rightFind;
    }
    如若在左右子树都没有找到,则说明找不到
    return NULL;
}

(7)二叉树的销毁 

//注意传入的是指针的地址,形参为二级指针
void BinaryTreeDestory(BTNode** root)
{
    if(*root == NULL)
    {
        return;
    }
    //销毁左右子树
    BinaryTreeDestory(&((*root)->left));
    BinaryTreeDestory(&((*root)->right));
    //销毁根结点
    free(*root);
    *root = NULL;
}

五、层序遍历

设⼆叉树的根结点所在层数为1,层序遍历就是从所在⼆叉树的根结点出发,首先访问第⼀层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,从左至右逐层访问树的结点的过程。

实现层序遍历需要额外借助数据结构:队列。

void LevelOrder(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    QueuePush(&q, root);
    while(!QueueEmpty(&q))
    {
        //取队头,并打印
        BTNode* front = QueueFront(&q);
        printf("%d ",front->val);

        //队头结点的左右孩子入队列
        if(front->left)
        {
            QueuePush(&q, front->left);
        }
        if(front->right)
        {
            QueuePush(&q, front->rught);
        }
    }
    //此时队列为空,销毁队列
    QueueDestroy(&q);
}

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

 

bool BinaryTreeComplete(BTNode* root) 
{
    Queue q;
    QueueInit(&q);
    QueuePush(&q, root);
    while (!QueueEmpty(&q))
    {
        BTNode* top = QueueFront(&q);
        QueuePop(&q);
        if (top == NULL) 
        {
            break;
        }
        QueuePush(&q, top->_left);
        QueuePush(&q, top->_right);
    }
    //队列不一定为空
    while (!QueueEmpty(&q))
    {
        BTNode* top = QueueFront(&q);
        QueuePop(&q);
        if (top != NULL) 
        {
            QueueDesTroy(&q);
            return false;
        }
    }
    QueueDesTroy(&q);
    return true;
}

如果是完全二叉树,跳出一个循环之后队列中剩下的全都是NULL结点;

如果不是完全二叉树,跳出一个循环之后队列中还有非空结点。 

七、写在最后

我们已经学习了实现二叉树的两种方法:顺序结构(堆)和链式结构。

敬请期待“二叉树OJ题”~

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

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

相关文章

【机器学习】逻辑回归的梯度下降以及在一变量数据集、两变量数据集下探索优化的梯度下降算法

引言 在机器学习中,逻辑回归是一种用于二分类问题的方法。它使用逻辑函数(也称为sigmoid函数)来预测属于某个类别的概率。逻辑回归的损失函数通常是交叉熵损失,用于衡量预测值与真实值之间的差异 文章目录 引言一、逻辑回归的梯度…

电机的伺服调试和pid调节有什么异同?

电机的伺服调试和PID调节在调节控制系统的精度和性能方面都是重要的,但它们有不同的侧重点和方法: 伺服调试 定义:伺服调试是指对伺服系统进行优化和调整,以确保其在控制对象(如电机)上的表现达到预期。伺…

《LeetCode热题100》---<5.②普通数组篇五道>

本篇博客讲解LeetCode热题100道普通数组篇中的六道题 第三道:轮转数组(中等) 第四道:除自身以外数组的乘积(中等) 第三道:轮转数组(中等) 方法一:使用额外的数…

KubeSphere 部署的 Kubernetes 集群使用 GlusterFS 存储实战入门

转载:KubeSphere 部署的 Kubernetes 集群使用 GlusterFS 存储实战入门 知识点 定级:入门级 GlusterFS 和 Heketi 简介 GlusterFS 安装部署 Heketi 安装部署 Kubernetes 命令行对接 GlusterFS 实战服务器配置(架构1:1复刻小规模生产环境,…

AI助力,轻松组建你的汽车梦之队!

咱汽车销售想增加目标客户,可不简单!市场竞争那叫一个激烈,吸引客户注意力太难了!不过别怕,咱有办法。我在 ai123.cn 这个平台上,找到了好多适合咱的 AI 工具和资源,这就跟大家分享分享。 比如说…

upload-labs漏洞靶场~文件上传漏洞

寻找测试网站的文件上传的模块,常见:头像上传,修改上传,文件编辑器中文件上传,图片上传、媒体上传等,通过抓包上传恶意的文件进行测试,上传后缀名 asp php aspx 等的动态语言脚本,查…

基于C语言从0开始手撸MQTT协议代码连接标准的MQTT服务器,完成数据上传和命令下发响应(华为云IOT服务器)

文章目录 一、前言二、搭建开发环境三、网络编程基础概念科普3.1 什么是网络编程3.2 TCP 和 UDP协议介绍3.3 TCP通信的实现过程 四、Windows下的网络编程相关API介绍4.1 常用的函数介绍4.2 函数参数介绍4.3 编写代码体验网络编程 五、访问华为云IOT服务器创建一个产品和设备5.2…

STM32ADC

ADC简介:有打moba游戏的别搞混了,这不是射手adc。在32中,ADC的全称为:Analog-to-Digital Converter,指模拟/数字转换器 也就是模拟-数字电路的转换器。其实通俗的来讲,它就是一个电压表。 目录 一.ADC原理…

六、5 TIM输入捕获介绍

1、基本知识介绍 (1) 注意: ①4个输入捕获和输出比较通道,共用4个CCR寄存器 ②CH1到CH4,四个通道的引脚也是共用的 ③同一个定时器输入捕获和输出比较,不能同时使用 (2)输入捕获…

4G/5G无线视频采集设备如何通过国标28181接入到视频监控接入平台(视频统一接入平台)

目录 一、国标GB/T 28181介绍 1、国标GB/T28181 2、内容和特点 二、4G/5G无线视频采集设备 1、定义 2、主要功能: 3、技术特点 4、应用场景 二、接入准备工作 1、确定网络环境 (1)公网接入 (2)专网传输 2、…

使用 Rough.js 创建动态水平条形图

本文由ScriptEcho平台提供技术支持 项目地址:传送门 使用 Rough.js 创建动态可视化网络图 应用场景 Rough.js 是一个 JavaScript 库,它允许开发人员使用毛边风格创建可视化效果。该库适用于各种应用程序,例如: 数据可视化地图…

【C++11】解锁C++11新纪元:深入探索Lambda表达式的奥秘

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:C11右值引用 🌹🌹期待您的关注 🌹🌹 ❀C11 📒1. 可变参数模板…

.net # 检查 带有pdf xss

1.解决pdf含javasprct脚本动作,这里是验证pdf内部事件。相关pdf文件下载: 测试pdf文件 相关包 iTextSharp 5.5.13.4 iTextSharp using iTextSharp.text.pdf; using iTextSharp.text.pdf.parser;private Boolean IsPdfSafe(Stream stream){// PdfReader…

PyTorch+PyG实现图神经网络经典模型目录

前言 大家好,我是阿光。 本专栏整理了《图神经网络代码实战》,内包含了不同图神经网络的相关代码实现(PyG以及自实现),理论与实践相结合,如GCN、GAT、GraphSAGE等经典图网络,每一个代码实例都…

洛谷 P1739 表达式括号匹配 题解

题目描述 假设一个表达式有英文字母(小写)、运算符(、-、*、/)和左右小(圆)括号构成,以 作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配&#xff0c…

springboot农产品报价系统-计算机毕业设计源码37300

摘 要 本研究基于鸿蒙系统,设计开发了一款农产品报价系统小程序,旨在帮助商家与买家更便捷、高效地进行交易。该系统利用鸿蒙系统的优势,实现了跨平台应用程序的开发,同时利用定位技术和数据采集技术,为用户提供了个性…

RoboCom 2021 编程技能赛决赛 7-4 猛犸不上 Ban

7-4 猛犸不上 Ban 赛题 分数 30 作者 DAI, Longao 单位 杭州百腾教育科技有限公司 在一个名叫刀塔的国家里,有一只猛犸正在到处跑着,希望能够用它的长角抛物技能来撞飞别人。已知刀塔国有 N 座城市,城市之间由 M 条道路互相连接&#xff…

【C语言】【数据结构】冒泡排序及优化

一、算法思想 冒泡排序是一种简单的排序算法。一次从前往后地走访待排序的元素序列被称为一趟,每一趟都会把相邻的两个元素的错误顺序交换,将当前趟次中最大或者最小的元素像“冒泡泡”一样冒到最后面,反复地走访元素序列,直到所有…

Maven 安装-从下载、安装、配置以及检查是否安装成功,最详细安装教程

以下内容参考:https://juejin.cn/post/6844903543711907848 原文标题:Maven入门,读完这篇就够了 作者:嘟嘟MD 链接:https://juejin.cn/post/6844903543711907848 来源:稀土掘金 ----- 注:所有流…

计算机组成原理——运算器ALU,移位操作

一、组合逻辑电路和时序逻辑电路 组合逻辑电路:其输出仅取决于当前输入组合,不依赖先前输出,不具备存储状态的能力 时序逻辑电路:其输出不仅取决于当前输入,还取决于先前的输出,具备存储状态的能力。 AL…