(二叉树)

我们今天就开始引进一个新的数据结构了:我们所熟知的:二叉树;

但是我们在引进二叉树之前我们先了解一下树;

树的概念和结构:

树是⼀种⾮线性的数据结构,它是由 n ( n>=0 ) 个有限结点组成⼀个具有层次关系的集合。把它叫做 树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。

有⼀个特殊的结点,称为根结点,根结点没有前驱结点。

除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1 、 T2 、 …… 、 Tm ,其中每⼀个集合 Ti(1 <= i <= m) ⼜是⼀棵结构与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以 有 0 个或多个后继。因此,树是递归定义的。

我们的树,我们的单个结点可以当作是一个树,加入我们的某一个结点是没有后代的,就是一个单个的结点,这也可以算作是一个树;

这就是我们的一个树,我们可以看到,我们的树的结点的分布是没有什么规律的,每个结点后面可以有很多个后继的节点,但是只有一个前驱结点,但是除了根结点是没有前驱结点的,我们的最后面的叶子结点也是没有后继结点的;

在我们的树形结构里面,我们的子树之间是不能有交集的,否则这就不是一个树形的结构了;这就是一个图了

看这几个就不是树的结构,树的结构他的子树是不能有交集的,这是图;也是一种数据结构,但是在这里我们不进行讲解;

当我们有一个树的结构的时候;这个二叉树就有了下面的名字;

因为我们的树的后面可以有很多个结点;没有对他进行限制,这就不是一个好的数据结构,我们在这里再次引入一个新的数据结构:二叉树

二叉树

概念和结构:

在树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点 加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空

我们观察上面的图片,我们就可以知道的结论:

1.二叉树的度是不大于2的,最多是二,度其实就是这个结点拥有的孩子的个数,而树的度就是我们的节点里面的度最大的结点的度就是我们的树的度;

2.二叉树是有左右子树之分的,这样的次序是不能颠倒的,二叉树是一个有序树;

3.任意的二叉树都是由以下的结点组成的

这些东西相互复合,最终就可以构成一个二叉树;

这个就是我们的现实生活里面可以见到的二叉树;是非常标准的

我们再来引入一些特殊的二叉树:

1.满二叉树;

⼀个⼆叉树,如果每⼀个层的结点数都达到最⼤值,则这个⼆叉树就是满⼆叉树。也就是说,如果⼀ 个⼆叉树的层数为 K ,且结点总数是2^k-1个 ,则它就是满⼆叉树。

这就是满二叉树的结点的运算方法;我们知道了满二叉树的高度k,就可以得出他的总的结点的个数;2^k-1;

把每一层的结点的个数拉满,这就是满的二叉树;

2.完全二叉树

完全二叉树就是由满二叉树演变来的,满二叉树其实就是特殊的完全二叉树;

完全二叉树除了最后一层,其他层的结点的个数都是满的,但是我们的最后一层,节点个数不一定是满的,它可以是满的,比如满二叉树,也可以不是满的,还是完全二叉树;

我们来看这个,这就是一个完全的二叉树,也是一个满二叉树。

我们再来看这个,这就不是一个完全的二叉树;

完全的二叉树,他的节点一定是集中的位于左边,如果不是慢的二叉树,他的最后一层的结点一定是按顺序从左往右的进行排列的。

这就不是一个完全的二叉树,完全二叉树的话,除了最后一层结点,其他的层的结点一定都是满的。

我们的完全二叉树的最后一层的结点一定是从左往右的进行排列的。

我们来说一下二叉树的性质:

我们再说一下二叉树的存储结构

顺序结构和链式结构;

顺序结构的存储就是使用数组来进行存储;但是这种存储方式一般只适用于完全二叉树,因为使用完全二叉树不会有内存空间的浪费;

现实中我们通常把堆(⼀种⼆叉树)使⽤顺序结构的数组来存储,需要注意的是这⾥的堆和操作系统 虚拟进程地址空间中的堆是两回事,⼀个是数据结构,⼀个是操作系统中管理内存的⼀块区域分段。

那我们就来实现一下堆二叉树

现实中我们通常把堆(⼀种⼆叉树)使⽤顺序结构的数组来存储,需要注意的是这⾥的堆和操作系统 虚拟进程地址空间中的堆是两回事,⼀个是数据结构,⼀个是操作系统中管理内存的⼀块区域分段。

堆又分为两种;1.大根堆 。2.小根堆

大根堆:根节点最大的堆,我们称作大根堆。

小根堆:根节点最小的堆,这就是小根堆。(要注意:我们的树的每一个子树的根节点都是最大或者最小的)。

顺序结构的存储使用的是完全的二叉树;这样可以减少空间的浪费;使用顺序结构来进行存储的时候,我们使用的完全二叉树就是堆二叉树

堆的性质:

1.堆二叉树里面的结点的值,总是不大于或者不小于其父节点的值;

2.堆二叉树是一颗完全二叉树;

我们再来看一下完全二叉树的性质:

1.当我们知道某一个结点的下标的时候,我们可以推断出其父节点的下标。(i-1)/2;  可以求出父节点下标;

2.当我们知道父节点的下标的时候,我们可以求出孩子结点的下标;但是我们求出来的孩子节点的下标是不能越界的,我们设置的结点的个数为n个,我们的数组最后一个结点所对应的下标为n-1,所以,我们求出来的孩子结点所对应的下标为2i+1<n,只有在这个范围里面才是有效的;

我们的右孩子的求法就是左孩子的下标加一;得到的就是右孩子的下标;而且我们的右孩子下标也是<n的,这是有效的;

我们的堆二叉树在逻辑结构上就是二叉树,但是在存储的结构上的底层是数组;

当我们往堆里面插入数据的时候,我们一开始是一个空的堆,也就是一个空的数组;

那我们使用代码来实现一下堆:

///堆二叉树的初始化
void HPInit(HP* php)
{
    assert(php);
    php->arr = NULL;
    php->capacity = php->size = 0;
}

//堆的销毁
void HPDestory(HP* php)
{
    assert(php);
    if (php->arr)
        free(php->arr);
    php->arr = NULL;
    php->capacity = php->size = 0;

}

void swap(int* x, int* y)
{
    int tmp = *x;
    *x = *y;
    *y = tmp;
}

//向上调整(入堆)
void Adjustup(HPDataType* arr, int child)
{
   //我们要进行向上调整,我们可以根据孩子把父亲求出来
    int parent = (child - 1) / 2;
    //向上调整既可以是大堆,也可以是小堆;
    
    while (child > 0)
    {
        //如果要求是小堆的时候,我们看谁小,我们就把谁往上放,
        //所以小堆:<
        //如果孩子比父亲小我们就交换
        //大堆:>
        //如果孩子比父亲大我们就交换
        if (arr[child] < arr[parent])
        {
            swap(&arr[child], &arr[parent]);
        }
        else
        {
            break;
        }
        child = parent;
        parent = (child - 1) / 2;
    }
}

void Print(HP* php)
{
    for (int i = 0; i < php->size; i++)
    {
        printf("%d ", php->arr[i]);
    }
    printf("\n");
}


//入堆  往堆里面插入数据
void HPPush(HP* php, HPDataType x)
{
    assert(php);//先进行一下断言,这个必须是一个有效的堆的数据结构;
    //判断空间是否足够;不够的话,我们就进行增容;
    if (php->capacity == php->size)
    {
        int Newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
        //当我们的arr是空指针的时候,我们也不需要担心,这个时候realloc的作用和malloc就是一样的;
        HPDataType* tmp = (HPDataType*)realloc(php->arr, Newcapacity * sizeof(HPDataType));
        if (tmp == NULL)
        {
            perror("realloc");
            exit(1);
        }
        php->arr = tmp;
        php->capacity = Newcapacity;
    }
    //然后我们直接把数据插入
    /*php->arr[php->size++] = x;*/
    //这个时候size还不能加加,因为我们还要使用size这个下标
    php->arr[php->size] = x;
    
    //然后向上进行调整;
    Adjustup(php->arr, php->size);
    php->size++;
}

//判空
//判断二叉树里面有没有数据
bool HPEmpty(HP* php)
{
    assert(php);
    return php->size == 0;
}

//向下调整法(出堆)
void AdjustDown(HPDataType* arr, int parent, int n)
{
    int child = 2 * parent + 1;//左孩子;

    while (child < n)
    {
        //大堆:<
        //大堆的话我们找到大孩子
        //小堆:>
        //小堆我们就找小孩子
        if (child + 1 < n && arr[child] < arr[child+1])
        {
            child++;
        }

        //大堆  >
        //我们找到大的放上去
        //小堆  <
        //我们找到小的放上去
        if (arr[child] > arr[parent])
        {
            swap(&arr[child], &arr[parent]);
            parent = child;
            child = 2 * parent + 1;
        }
        else
        {
            break;
        }
    }
}

//出堆 -- 出堆指的是出堆顶数据;
void HPPop(HP* php)
{
    //我们把栈顶的数据给他出出去

    //出堆的话,堆里面一定是不能为空的
    assert(!HPEmpty(php));
    //我们的出堆的方式是先让第一个数据和最后一个数据进行交换;
    //然后让有效的数据减一,然后进行排序
    swap(&php->arr[0], &php->arr[php->size - 1]);
    //这时候我们的堆顶的数据放到了最后一个位置
    php->size--;
    //然后我们这里使用向下调整法;从堆顶往下进行调整
    AdjustDown(php->arr, 0, php->size);
    //我们要把数组传过去,还有我们的parent的下标0;然后还有有效的数据个数;
}


//取堆顶数据
HPDataType HPTop(HP* php)
{
    assert(!HPEmpty(php));
    //我们要取堆顶元素,那么我们的堆就不能为空堆二叉树;
    return php->arr[0];
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

洛谷P8837

[传智杯 #3 决赛] 商店 - 洛谷 代码区&#xff1a; #include<stdio.h> #include<stdlib.h> int cmp(const void*a,const void *b){return *(int*)b-*(int*)a; } int main(){int n,m;scanf("%d%d",&n,&m);int w[n];int c[m];for(int i0;i<n;…

C语言练习(17)

两个乒乓球队进行比赛&#xff0c;各出3人。甲队为A、B、C 3人&#xff0c;乙队为X、Y、Z 3人&#xff0c;并抽签决定比赛名单。有人向队员打听比赛的名单&#xff0c;A说他不和X比&#xff0c;C说他不和X、Z比&#xff0c;请编程序找出3对选手的对阵名单。 #include <stdi…

excel实用工具

持续更新… 文章目录 1. 快捷键1.1 求和 2. 命令2.1 查找 vloopup 1. 快捷键 1.1 求和 windows: alt mac : command shift T 2. 命令 2.1 查找 vloopup vlookup 四个入参数 要查找的内容 &#xff08;A2 6xx1&#xff09;查找的备选集 &#xff08;C2:C19&#xff09;…

【高阶数据结构】布隆过滤器(BloomFilter)

1. 概念 1.1 背景引入 背景&#xff1a;在计算机软件中&#xff0c;一个常见的需求就是 在一个集合中查找一个元素是否存在 &#xff0c;比如&#xff1a;1. Word 等打字软件需要判断用户键入的单词是否在字典中存在 2. 浏览器等网络爬虫程序需要保存一个列表来记录已经遍历过…

Linux内存管理(Linux内存架构,malloc,slab的实现)

文章目录 前言一、Linux进程空间内存分配二、malloc的实现机理三、物理内存与虚拟内存1.物理内存2.虚拟内存 四、磁盘和物理内存区别五、页页的基本概念&#xff1a;分页管理的核心概念&#xff1a;Linux 中分页的实现&#xff1a;总结&#xff1a; 六、伙伴算法伙伴算法的核心…

2025/1/21 学习Vue的第四天

睡觉。 --------------------------------------------------------------------------------------------------------------------------------- 11.Object.defineProperty 1.在我们之前学习JS的时候&#xff0c;普通得定义一个对象与属性。 <!DOCTYPE html> <h…

机器学习10-解读CNN代码Pytorch版

机器学习10-解读CNN代码Pytorch版 我个人是Java程序员&#xff0c;关于Python代码的使用过程中的相关代码事项&#xff0c;在此进行记录 文章目录 机器学习10-解读CNN代码Pytorch版1-核心逻辑脉络2-参考网址3-解读CNN代码Pytorch版本1-MNIST数据集读取2-CNN网络的定义1-无注释版…

python学opencv|读取图像(四十)掩模:三通道图像的局部覆盖

【1】引言 前序学习了使用numpy创建单通道的灰色图像&#xff0c;并对灰色图像的局部进行了颜色更改&#xff0c;相关链接为&#xff1a; python学opencv|读取图像&#xff08;九&#xff09;用numpy创建黑白相间灰度图_numpy生成全黑图片-CSDN博客 之后又学习了使用numpy创…

【MySQL篇】使用mysqldump导入报错Unknown collation: ‘utf8mb4_0900_ai_ci‘的问题解决

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;从事IT领域✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对SQLserver、NoSQL(…

WPF2-在xaml为对象的属性赋值

1. AttributeValue方式 1.1. 简单属性赋值1.2. 对象属性赋值 2. 属性标签的方式给属性赋值3. 标签扩展 (Markup Extensions) 3.1. StaticResource3.2. Binding 3.2.1. 普通 Binding3.2.2. ElementName Binding3.2.3. RelativeSource Binding3.2.4. StaticResource Binding (带参…

软考 系统架构设计师系列知识点之面向服务架构设计理论与实践(5)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之面向服务架构设计理论与实践&#xff08;4&#xff09; 所属章节&#xff1a; 第15章. 面向服务架构设计理论与实践 第2节 SOA的发展历史 15.2 SOA的发展历史 15.2.3 SOA的微服务化发展 随着互联网技术的快速发展&a…

ICLR顶会论文学习|DRL-based改进启发式求解方法JSSP

论文名&#xff1a;Deep Reinforcement Learning Guided Improvement Heuristic for Job Shop Scheduling Authors: Cong Zhang, Zhiguang Cao, Wen Song, Yaoxin Wu, Jie Zh… 论文发表致&#xff1a;ICLR 2024 论文链接&#xff1a;https://doi.org/10.48550/arXiv.2211.1…

OpenCV简介、OpenCV安装

OpenCV简介、OpenCV安装 本文目录&#xff1a; 零、时光宝盒 一、OpenCV简介 二、OpenCV图像处理基础知识 三、OpenCV-Python环境安装 2.1、纯python环境下安装OpenCV 2.2、Anaconda管理环境下安装 OpenCV 四、如何用OpenCV 中进行读取展示图像 五、OpenCV读取图像、显…

利用预训练检查点进行序列生成任务

摘要 大型神经模型的无监督预训练最近彻底改变了自然语言处理。通过从公开发布的检查点进行热启动&#xff0c;自然语言处理从业者在多个基准测试中推动了最先进的技术&#xff0c;同时节省了大量的计算时间。到目前为止&#xff0c;重点主要集中在自然语言理解任务上。在本文…

5、原来可以这样理解C语言_数组(5)sizeof 计算数组元素个数

目录 5. sizeof 计算数组元素个数 5. sizeof 计算数组元素个数 在遍历数组的时候&#xff0c;我们经常想知道数组的元素个数&#xff0c;那C语⾔中有办法使⽤程序计算数组元素个数 吗&#xff1f; 答案是有的&#xff0c;可以使⽤sizeof。 sizeof 中C语⾔是⼀个关键字&#xff…

vue中echarts-中国地图,世界地图显示(echarts5.6版本本地导入)

地图去掉南海诸岛右下角的框显示&#xff08;因为显示的不是现在的10段线&#xff09; 资源里面主要是有个改好的中国地图json其他的无所谓&#xff0c;用现有的json也行&#xff0c;主要是为了解决10段线的问题 引入需要注意 import * as echarts from “./echarts”; 目录…

Ubuntu系统更改IP,保姆级教程

原理概述 本篇文章所用工具&#xff1a; Xshell&#xff1a;点击下载 VMware Workstation Pro&#xff1a;点击下载 密钥需要自行搜索所下载的VMware对应版本密钥。 IP 地址 IP 地址&#xff08;Internet Protocol Address&#xff09;是分配给每个连接到计算机网络的设备的…

IO进程----进程

进程 什么是进程 进程和程序的区别 概念&#xff1a; 程序&#xff1a;编译好的可执行文件 存放在磁盘上的指令和数据的有序集合&#xff08;文件&#xff09; 程序是静态的&#xff0c;没有任何执行的概念 进程&#xff1a;一个独立的可调度的任务 执行一个程序分配资…

使用插件SlideVerify实现滑块验证

作者gitee地址&#xff1a;https://gitee.com/monoplasty/vue-monoplasty-slide-verify 使用步骤&#xff1a; 1、安装插件 npm install --save vue-monoplasty-slide-verify 2、在main.js中进行配置 import SlideVerify from vue-monoplasty-slide-verify; Vue.use(SlideV…

初探——【Linux】程序的翻译与动静态链接

我们所写的C/C程序计算机是看不懂的&#xff0c;它只认识0101这样的机器码。所以我们就需要借助编译器对这些源代码进行翻译&#xff0c;使之成为计算机能够执行的二进制指令。这个过程通常分为几个关键步骤&#xff1a;预处理、编译、汇编和链接。 一.预处理&#xff08;Prep…