数据结构——二叉树基础结构篇(C语言)

news2024/11/19 19:26:59

引言

现在是北京时间2023年6月13日9点11分。从决定要开始减脂之后,饥饿总是伴随着我。一觉起来肚子咕咕叫,我还是想先把文章发了再吃第一餐。燕麦加蛋白粉几乎伴随了我大学的第一年早饭。昨天练了一个小时背,练背后还做了45分钟有氧。空腹训练没有影响我的训练状态。这一点我还是比较舒服的。坚持锻炼是一个不错的习惯也恳请你务必多多锻炼自己的身体,身体就是自己最宝贵的财富。
在这里插入图片描述

前言

本篇文章讲解的主要是二叉树的结构以及操作,对于学习二叉树来说先了解它的使用,再回过头去学习它的底层原理等效果会更好。所以,我就简单模拟实现了一个简单二叉树,等结构和用法都了解的差不多了再研究二叉树真正创建的方式。

typedef int BTDataType;

typedef struct BinaryTreeNode
{
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
    BTDataType data;
    
}BTNode;

BTNode* BuyNode(BTDataType x)
{
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    if (node == NULL)
    {
        perror("malloc fail");
        return NULL;
    }

    node->data = x;
    node->left = NULL;
    node->right = NULL;

    return node;
}

BTNode* CreatTree()
{
    BTNode* node1 = BuyNode(1);
    BTNode* node2 = BuyNode(2);
    BTNode* node3 = BuyNode(3);
    BTNode* node4 = BuyNode(4);
    BTNode* node5 = BuyNode(5);
    BTNode* node6 = BuyNode(6);
    BTNode* node7 = BuyNode(7);


    node1->left = node2;
    node1->right = node4;
    node2->left = node3;
    node4->left = node5;
    node4->right = node6;
    node3->right = node7;

    return node1;
}

简单回顾

这里简单回顾一下二叉树的概念。二叉树又分为空二叉树和非空二叉数两种。非空二叉树有两个部分构成:根和子树,子树又可以分成根和子树。
在这里插入图片描述

二叉树的遍历

二叉树的遍历大致分为四种,前序遍历、中序遍历、后序遍历、层序遍历。下面我们就了解一下各种的遍历方式。
在这里插入图片描述

前序遍历

实现思路大致如下,采取递归的思想进行遍历。递归的结束条件为遍历的结点为空就结束。

void PreOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return;
    }

    printf("%d ",root->data);
    PreOrder(root->left);
    PreOrder(root->right);
}

在这里插入图片描述

在这里插入图片描述

中序遍历

与前序遍历的的代码逻辑大致一样,只是访问根的顺序时机不同。本质上还是一样的思想。

void InOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return;
    }

    InOrder(root->left);
    printf("%d ", root->data);
    InOrder(root->right);
}

在这里插入图片描述

后序遍历

void PosOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return;
    }

    PosOrder(root->left);
    PosOrder(root->right);
    printf("%d ", root->data);
}

在这里插入图片描述

求树结点总数

求节点的总个数的思路就是用分治的思想。只要节点不为NULL就表示有一个结点,然后将左右子树的结点总数的和加上1(1即根结点)就能求出当前结点的总数。二叉树是可以不断地拆分成根和左右子树的,其实递归的核心就是处理一个个与原问题类似的子问题。
在这里插入图片描述

int TreeSize(BTNode* root)
{
    return root == NULL ?
            0 :
            TreeSize(root->left)
            +TreeSize(root->right)
            +1;
}

在这里插入图片描述

求树的高度

求树的高度也可以采取分治的思路。如果说上面的求结点总数是校长求全校的人数,那么求树的高度其实就是找全校最高的人。实现思路如下,找左右子树中较大的那个加上根节点的高度就是树的高度。
在这里插入图片描述

int TreeHeight(BTNode* root)
{
    if(root == NULL)
        return 0;
    
    int lh =TreeHeight(root->left);
    int rh =TreeHeight(root->right);
    
    return lh > rh ? lh+1 : rh+1;
}

在这里插入图片描述

求第k层节点个数

求第k层的结点个数本质就是求左子树第k-1个结点个数+右子树第k-1层结点个数的和。
在这里插入图片描述

int TreeKLevel(BTNode* root, int k)
{
    if(root == NULL)
        return 0;
    if(k == 1)
        return 1;
    int lk = TreeKLevel(root->left, k-1);
    int rk = TreeKLevel(root->right, k-1);
    
    return lk+rk;
    
}

在这里插入图片描述

单值二叉树问题

在这里插入图片描述
本题的解题的思路有很多,如遍历、分治等。当然这里比较推荐实用分治的思想来进行解决这种二叉树的很多问题中,遍历的结局思路是不如分治的。下面就简单的介绍一下思路。首先,要将结点为空的情况考虑进去。其次,判断左右子结点是否存在且值不相等的情况。最后,分治递归进行比较判断,只要有一个不相等整体就是不为等值二叉树。
在这里插入图片描述

在这里插入图片描述

二叉树的查找

二叉树的查找接口,它的作用不仅仅是查找到该结点,还可以作为获取想要修改结点的地址的一个方式。实现思路主要是以递归的思想进行遍历整棵树。如果结点的值==val,那就返回这个结点的地址。

BTNode* BTFind(BTNode* root, int x)
{
    if(root == NULL)
    {
        return NULL;
    }
    //判断
    if(root->data == x)
        return root;
    //NULL不返回,找到了才返回
    BTNode* lret = BTFind(root->left, x);
    if(lret)
        return lret;
    BTNode* rret = BTFind(root->right, x);
    if(rret)
        return rret;
    //走到此处表示没有找到结点
    return NULL;
}

相同二叉树

在这里插入图片描述
解决本问题的思路如下,首先,考虑根节点都为空的情况以及其中是一个根结点为空的情况下。然后递归判断左右子树值是否相等即可。
在这里插入图片描述

前序遍历oj

在这里插入图片描述
主要介绍的是接口型oj的特点。这里的returnSize是一个输出型参数,传递的局部变量标识数组长度变量的地址,要求我们写入动态开辟数组的长度。作为返回值的数组要用存放在堆区(动态申请)的数组。若使用局部定义的数组,在函数调用结束后就会销毁,就无法的到遍历后的结果,也会有野指针问题。
在这里插入图片描述

解题思路如下,先求出树的结点总数,然后,根据树的结点总数来malloc申请空间。最后,在创建一个局部变量来作为标记数组下标,前序遍历将数据写入数组中。
在这里插入图片描述

另一棵树的子树

在这里插入图片描述
解题思路如下,首先,root == NULL时,那就不可能是匹配和subRoot的一样的子树。然后,这里可以复用之前写的判断两树是否相同的代码,用每个根节点进行匹配,然后,递归分治找到匹配的子树就返回真,否则返回假。
在这里插入图片描述

层序遍历

二叉树的层序遍历实现思路如下,将根节点入队列,遍历根节点后,判断根的左右节点是否为NULL,不为NULL就入队列。循环往复直到队列为空就结束层序遍历。点击获取队列实现代码。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

判断是否为完全二叉树

本接口实现主要思路是根据层序遍历,完全二叉树第一个NULL结点后面不会出现非空结点。实现步骤依旧是层序遍历的思路,当出到第一个NULL结点时,便不再让数据入队,遍历剩下的结点。当出现非空结点即表示不是完全二叉树,若全为空结点则表示为完全二叉树。
在这里插入图片描述

在这里插入图片描述

二叉树的销毁

采取后序遍历的思想进行对节点的释放。这里实现的版本为一级指针作为参数,需要调用本函数后手动置空。
在这里插入图片描述

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

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

相关文章

BeautifulPrompt:PAI推出自研Prompt美化器,赋能AIGC一键出美图

作者:曹庭锋、汪诚愚、吴梓恒、黄俊 背景 Stable Diffusion(SD)是一种流行的AI生成内容(AI Generated Content,AIGC)模型,能在文字输入的基础上生成各种风格多样的图像。在目前的AIGC方向&…

十五周算法训练营——普通动态规划(上)

今天是十五周算法训练营的第十一周,主要讲普通动态规划(上)专题。(欢迎加入十五周算法训练营,与小伙伴一起卷算法) 斐波那契数 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那…

设计模式——适配器模式

1.定义 将一个类的接口转换成客户所希望的另一个接口,Adapter模式使得那些原本因为接口不兼容而不能一起工作的那些类可以一起工作。 2.使用场景 一般来说,适配器模式可以看作一种“补偿模式”,用来补救设计上的缺陷。应用这种模式算是“无…

驱动开发:内核LoadLibrary实现DLL注入

远程线程注入是最常用的一种注入技术,在应用层注入是通过CreateRemoteThread这个函数实现的,该函数通过创建线程并调用 LoadLibrary 动态载入指定的DLL来实现注入,而在内核层同样存在一个类似的内核函数RtlCreateUserThread,但需要…

【模型评估】AP 和他们的兄弟们:mAP、AP50、APs、APm、APl

AP是在目标检测任务中,尝尝被用于评估模型预测能力的指标。那AP是什么?为什么能够充当不同模型综合对比评测的公认指标呢? 在学习下文之前,混淆矩阵和ROC可以先了解下: 【模型评估】混淆矩阵(confusion_m…

世界中西医结合医学研究院一行莅临万民健康交流指导

为进一步发展中医药产业,深入挖掘中医药文化,坚持中西医并重,传承精华,守正创新,助力乡村振兴、促进乡村医疗产业发展。6 月 10 日 , 世界中西医结合医学研究院医学工程院院士罗先义 、谈家桢生命基金会主任…

测试左移及其相关实践

本文首发于个人网站「BY林子」,转载请参考版权声明。 之前在《敏捷测试的核心》、《构建测试的体系化思维(进阶篇)》和《一页纸测试策略》等文章中提到过测试左移,但是没有专门针对这个主题做过系统的介绍,但又总是被社…

M4内核的FPU/DSP使用总结

FPU简介 近年,在Cortex-M3之后ARM公司又推出Cortex-M4内核,ARM Cortex-M4处理器是由ARM专门开发的最新嵌入式处理器,在M3的基础上强化了运算能力,新加了浮点、DSP、并行计算等。Cortex-M4处理器的最大亮点之一,也是本文…

dom-to-image分享多张异步图片遇到的坑

dom-to-image库 存在的问题 github-issue地址 问题:当超过一张图片时,ios/safari首次会出现某张图片空白,再次生成canvas才正常。 之前有一张图片时通过执行2次domtoimage.toJpeg(魔法),当超过1张图片时&a…

JavaWeb笔记(一)

Java网络编程 在JavaSE阶段,我们学习了I/O流,既然I/O流如此强大,那么能否跨越不同的主机进行I/O操作呢?这就要提到Java的网络编程了。 **注意:**本章会涉及到计算机网络相关内容(只会讲解大致内容&#x…

PyTorch 深度学习 || 专题八:PyTorch 全连接网络分类

PyTorch 全连接网络分类 文章目录 PyTorch 全连接网络分类1. 非线性二分类2. 泰坦尼克号数据分类2.1 数据的准备工作2.2 全连接网络的搭建2.3 结果的可视化 1. 非线性二分类 import sklearn.datasets #数据集 import numpy as np import matplotlib.pyplot as plt from sklear…

Java企业级信息系统开发学习笔记(4.2)Spring Boot项目单元测试、热部署与原理分析

该文章主要为完成实训任务,详细实现过程及结果见【http://t.csdn.cn/pG623】 文章目录 一、Spring Boot单元测试概述1.1 对项目HelloWorld01进行单元测试1. 添加测试依赖启动器和单元测试2. 创建测试类与测试方法 1.2 对项目HelloWorld02进行单元测试1. 添加单元测试…

C++冷知识:构造函数初始化时,为什么使用 : 而不是使用作用域内初始化对象?

:是什么? 这样的行为被称之为初始化列表。具体展示如下: 直接初始化对象。 以一个线程池类为例: class ThreadPool { public:// 构造函数,创建指定数量的线程ThreadPool(size_t num_threads) : stop(false){....}// 析构函数&…

【计算摄影学】总目录

1.数码相机 《数码相机中的图像传感器和信号处理》和《光与赢的魔幻乐园有趣的透镜》 1.1 数码相机概览 1.2 数码相机中光学系统 2.图像传感器 《数码相机中的图像传感器和信号处理》和《智能cmos图像传感器与应用》 2.1 图像传感器基础知识 2.2 CCD图像传感器 2.3 CMOS图像…

RankNet方法在移动终端的应用

RankNet方法在移动终端的应用 RankNet代码示例pythonJava 移动终端的应用 RankNet RankNet 是一种排序学习方法,由 Microsoft Research 提出,用于解决排序问题。它基于神经网络,并使用一对比较的方式来训练和优化模型。 在 RankNet 中&…

你的企业还没搭建这个帮助中心网页,那你太落后了!

作为现代企业,拥有一个完善的帮助中心网页已经成为了不可或缺的一部分。帮助中心网页不仅可以提供给用户有关产品或服务的详细信息,还可以解答用户的疑问和提供技术支持,使用户在使用产品或服务时遇到问题可以很快地得到解决。因此&#xff0…

内网隧道代理技术(四)之NETSH端口转发

NETSH端口转发 NETSH介绍 netsh是windows系统自带命令行程序,攻击者无需上传第三方工具即可利用netsh程序可进行端口转发操作,可将内网中其他服务器的端口转发至本地访问运行这个工具需要管理员的权限 本地端口转发 实验场景 现在我们有这么一个环境…

AntDB存储技术——水平动态扩展技术

数据库集群安装完成后,其数据存储容量是预先规划并确定的。随着时间的推移以及业务量的增加,数据库集群中的可用存储空间不断减少,面临数据存储容量扩充的需求。 通过增加数据节点,扩充集群数据容量,必然需要对已有数…

云服务器是什么? 云服务器有哪些选择?

欢迎前往我的个人博客云服务器查看更多关于云服务器和建站等相关文章。 随着互联网技术的发展和云计算技术的应用,越来越多的企业倾向于使用云服务器来满足其不断增长的计算需求。云服务器是一种基于云计算技术的虚拟服务器,它能够为企业提供高性能、可…

创业很长时间以后

创业过很长时间以后…综合能力是有滴 创业和打工后的思维习惯 为了效率,一般情况是这样滴 趣讲大白话:区别还是有滴 【趣讲信息科技195期】 **************************** 创业还是很难滴 每年成立很多新公司 有很多公司关门 公司平均生存时间&#xff1…