二叉树的顺序存储与手撕数据结构—堆

TIPS

  1. 树的话是一种非线性的数据结构,他实际上就是具有一定层次关系的数据集合,并且在树形结构当中,子树之间不能有任何的交集,否则就不是树形结构。然后对于树而言的话,在实际应用当中并不是特别多,在实际应用当中用的特别多的是二叉树。

  1. 对于二叉树这个概念而言,千万不能把二叉树等价于有完全二叉树,实际上二叉树的话,它的样子的话也可以千奇百怪,诸如

  1. 因为二叉树他的条件就是说整个树的度<=2就可以了,所以上面这种形态的也可以称之为二叉树,然后平时的接触到的比较多的,一般都是满二叉树或完全二叉树

  1. 然后就是关于二叉树节点数量的一些性质:首先是对于任何一棵树而言,度数为0的节点的数量一定比度数为一的节点的数量要多一;然后对于完全二叉树而言,度数为一的点,要么是零,要么是一;接下来在树的第k层当中,节点的数量最多是2的k减1次方,有k层节点的树最多拥有的节点数量是2的k次方减1


完全二叉树高度&深度估算(为后面的堆有关复杂度做铺垫)

  1. 如果说一个完全二叉树(满二叉树是完全二叉树的一种特殊情况),他有n个节点的话,那么这时候他的层数(不是精确计算,而是大概估量一下)他的层数是logN

  1. 这个概念非常重要,因为涉及到之后的一个堆排序的一个时间复杂度与效率的计算问题


拉响警报:堆正式降临!!!!!!!!!!!!!!!!!!


二叉树的顺序存储(仅局限于堆与完全二叉树)

  1. 对于二叉树而言,它有两种存储方式,一种就是顺序结构,一种是链式结构。

  1. 首先,逻辑结构与物理结构的区别还是得知道,在逻辑结构上的话,它是一棵树,但是如果在物理结构上的话,他就是一个数组。逻辑结果的话是想象出来的,有可能与物理结构是一样的,比如说顺序表;有可能是与物理结构不一样的,比如链表或者二叉树。物理结构的话,相当于就是说是实实在在在内存当中是如何存储的。

  1. 顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,关于堆我们后面的章节会专门讲解。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

  1. 其实要存储的话应该比较简单,就是把这个树里面的一层一层的数据依次往数组里面去存。用数组储存二叉数的话,并不适合随便乱七八糟的一个二叉树,是比较适合满二叉树或者说完全二叉树。如果一个二叉树它并不符合完全二叉树的话,这时候用数组去存储的话,当然也是可以,但是有很多位置会空缺出来,这就会形成浪费。因此的话,用数组去存储二叉数的话是带有局限性。数组存储表示二叉数只适合完全二叉树。

  1. 然后需要注意的是就是说二叉树当中每一个节点的下标与数组当中的下标都是一一对应的,见一开始的图。

就可以通过孩子的下标去找到他的父节点的下标。主要是他们之间的下标关系有这样一个结论:parent = (child -1)/2, 然后如果说已经知道父结点的下标,我这时候想要去求他的两个左右儿子的下标,这也非常的简单:主要是他们之间的下标有这样一种关系 leftchild=parent*2+1,rightchild=parent*2+2


堆(二叉树->完全二叉树->儿子总是小于(大于)父亲

  1. 如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1,…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

  1. 堆的性质:堆中某个节点的值总是不大于或不小于其父节点的值;堆总是一棵完全二叉树。

  1. 堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

  1. 堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

  1. 堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

  1. 堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

  1. 堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

  1. 堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

  1. 堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

小根堆与大根堆


手撕数据结构—堆(底层为顺序表)

堆的结构体创建

typedef int HeapDataType;
typedef struct Heap
{
    HeapDataType data;
    int size;
    int capacity;
}heap;

堆的结构体初始化

#define INIT_CAPACITY 5
void HeapInit(heap* php)
{
    assert(php);
    php->p = (HeapDataType*)malloc(sizeof(HeapDataType) * INIT_CAPACITY);
    if (php->p == NULL)
    {
        perror("malloc fail");
        return;
    }
    php->capacity = INIT_CAPACITY;
    php->size = 0;
}

堆的数组元素交换函数

void Swap(HeapDataType* p1, HeapDataType* p2)
{
    HeapDataType tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

堆的向上更新(以大根堆为例)

void AdjustUp(HeapDataType* a, int child)
{
    assert(a);
    int parent=(child-1)/2;
    while (child > 0)
    {
        int parent = (child - 1) / 2;
        if (a[child] > a[parent])
        {
            Swap(a + child, a + parent);
            child = parent;
            parent=(child-1)/2;
        }
        else
        {
            break;
        }
    }
}

堆的向下更新(以大根堆为例)

void AdjustDown(HeapDataType* a, int parent, int n)
{
    assert(a);
    int child = (parent * 2 + 1);
    while (child<n)
    {
        if (child+1< n && a[parent * 2 + 1] < a[parent * 2 + 2])
        {
            child++;
        }
        if (a[parent] >= a[child])
        {
            break;
        }
        else
        {
            Swap(a + parent, a + child);
            parent = child;
            child = parent * 2 + 1;
        }
    }
}

堆的往里面插入一个数值

void HeapPush(heap* php, int x)
{
    assert(php);
    if (php->size == php->capacity)
    {
        HeapDataType* tmp = (HeapDataType*)realloc(php->p, sizeof(HeapDataType) * php->capacity * 2);
        if (tmp == NULL)
        {
            perror("realloc fail");
            return;
        }
        php->p = tmp;
        php->capacity *= 2;
    }
    php->p[php->size] = x;
    php->size++;
    AdjustUp(php->p, php->size - 1);
}

堆的删除堆顶元素(堆中最值)

  1. 删除堆顶元素,如果在数组那边直接删的话,不仅会导致效率低下,因为需要流动数据,而且会导致父子关系全乱了

void HeapPop(heap* php)
{
    assert(php);
    assert(!HeapEmpty(php));
    Swap(php->p + 0, php->p + php->size - 1);
    php->size--;
    AdjustDown(php->p, 0, php->size);
}

堆的求堆顶元素(堆中最值)

int HeapTop(heap* php)
{
    assert(php);
    assert(!HeapEmpty(php));
    return php->p[0];
}

堆的判断是否为空

bool HeapEmpty(heap* php)
{
    assert(php);
    return php->size == 0;
}

堆的求堆中元素个数

int HeapSize(heap* php)
{
    assert(php);
    return php->size;
}
  1. 首先我们需要知道的是:堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)

  1. 然后堆中的元素的话并不都是有序的,这个是一个常见的认知误区,尤其对于我这种新手来说。根据堆的定义,它的条件其实说多也不多,说少也不少,他只限定了每个父亲与儿子之间值的大小关系,从整体而言,这个堆的话并不一定是有序的。

  1. 虽然并不一定是有序的,我们可以把这个堆称之为半有序状态因为他也并不是完全无序的,首先对于每一对父亲与儿子之间的大小关系是统一确定的,同时堆顶元素的话也有特殊的含义,堆顶元素整个堆当中所有数据的最值,这一点倒也是毋庸置疑的

  1. 然后需要有一种意识:就是你实际上操控的无非就是一个顺序表,说白了就是数组,但是逻辑结构与物理结构之间能够建立联系,说你要想象成你在操控着一颗完全二叉树

  1. 任何一个数组,其实如果你看待视角改变一下的话,都可以把它看成一颗完全二叉树,当然是不是堆的话就不一定了,还是那句话:堆=二叉树->完全二叉树->儿子总是小于(大于)父亲即可 (总的条件说多也不多,说少也不少)


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

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

相关文章

Linux防火墙——SNAT、DNAT

目录 NAT 一、SNAT策略及作用 1、概述 SNAT应用环境 SNAT原理 SNAT转换前提条件 1、临时打开 2、永久打开 3、SNAT转换1&#xff1a;固定的公网IP地址 4、SNAT转换2&#xff1a;非固定的公网IP地址&#xff08;共享动态IP地址&#xff09; 二、SNAT实验 配置web服务…

力扣-银行账户概要 II

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;1587. 银行账户概要 II二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果前言 …

css总结12(盒子模型外篇)

前言 主要补充一下和盒子模型相关的一些样式属性&#xff1a;box-sizing、resize和outline box-sizing 可选值 ## (1) content-box 默认值&#xff0c;内容盒子&#xff0c;盒子的大小会随着内容(盒子模型的content)尺寸的变化而变化 ## (2) border-box边框盒子&#xff0c;与…

leetcode究极刷题笔记(16~20)

&#xff08;16&#xff09;最接近的三数之和&#xff08;中等&#xff09; 实现思路&#xff1a; 本题与前文讲的三数之和有相同之处&#xff0c;但是本题求的是最接近的三数之和&#xff0c;所以我们这里可以使用键值对来映射对应的差值与值的关系&#xff0c;从而达到目的。…

系统集成路由器OSPF动态、综合路由配置

实验任务&#xff1a;动态路由协议RIP、OSPF协议的内容和特点动态路由RIP、OSPF实验&#xff0c;建立拓扑pc1>>R1>>R2>>R3>>pc2&#xff0c;使pc1与pc2能相互通信&#xff0c;并配置PC端静默接口。熟悉配置vlan间路由技术&#xff1a;多层交换机虚拟接…

JavaScript到底如何存储数据?

1.var的迷幻操作 普遍的观点&#xff1a;JavaScript中的基本数据类型是保存在栈空间&#xff0c;而引用数据类型则是保存在堆空间里, 是否正确&#xff1f; 浏览器环境下JavaScript变量类型的运行实践结果: var a 10;console.log(a);console.log(window.a); console.log(wind…

【云原生】Linux进程控制(进程程序替换)

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f38a;每篇一句&#xff1a; 图片来源 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 Good judgment comes from experience, and a lot of that comes from bad jud…

keepalived配置使用

keepalived安装tar -zxvf ***yum install -y gcc gcc-c wget popt-devel openssl openssl-devel yum install -y libnl libnl-devel libnl3 libnl3-devel yum install -y libnfnetlink-devel ./configure --sysconf/etc make make installmaster1 编辑keepalived的配置文件keep…

【C++】科普:C++中的浮点数怎么在计算机中表示?

这里我们以8.25这个数为例说明计算机时如何存取float类型的数据的&#xff1a; float a 8.25;引言 1. 所占位数 首先&#xff0c;明确一个概念&#xff0c;float类型的数据在常规计算机中通常占4个字节&#xff0c;也就是32位。其内存分布如图&#xff1a; 位字段说明所占位…

【pytorch源码剖析系列】优化器

写在前言&#xff1a;pyotrch优化器从源码的角度带你理解优化器的由来&#xff0c;实现&#xff0c;作用。pytorch的优化器&#xff1a;管理并更新模型中可学习参数的值&#xff0c;使得模型输出更接近真是标签。导数&#xff1a;函数在指定坐标轴上的变化率方向导数&#xff1…

ChatGPT来了你慌了吗?

文章目录一、ChatGPT是什么&#xff1f;一、ChatGPT到底多强大&#xff1f;三、各平台集成了ChatGPT插件&#xff1a;四、ChatGPT能否取代程序员&#xff1f;一、ChatGPT是什么&#xff1f; ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&…

快速上手vue elementUI好看的登录界面

这是一个非常非常适合新手的vue登录界面&#xff0c;总体来说美观大气&#xff0c;axios那部分没有发&#xff0c;有需要的大家可以自己进行二次开发&#xff0c;继续编写。 用到了技术栈有 vue/cli 5.07 element-ui 2.15.9 适合入门级新手&#xff0c;展示下页面 emmm验证码…

【Spring Cloud Alibaba】2.服务注册与发现(Nacos安装)

文章目录环境要求简介安装Nacos源码安装Docker安装数据库配置访问服务我们要搭建一个Spring Cloud Alibaba项目就绕不开Nacos&#xff0c;阿里巴巴提供的Nacos组件&#xff0c;可以提供服务注册与发现和分布式配置服务&#xff0c;拥有着淘宝双十一十几年的流量经验&#xff0c…

关于docker mysql 请求速度慢的问题

一&#xff0c;问题描述&#xff1a; 请求mysql 数据库&#xff0c;请求速度很慢&#xff0c;需要六七秒&#xff0c;数据量也不大。使用的是docker 容器启动的mysql 二&#xff0c;问题原因&#xff1a; 网上说的是因为MySQL的dns导致&#xff0c;我实测也是有效果的&#xf…

Linux:主机USB设备驱动简析

文章目录1. 前言2. 分析背景3. USB 总线硬件拓扑4. USB 协议栈概览4.1 Linux USB 子系统概览4.2 USB外设(如U盘)固件基础5. Linux USB 子系统初始化6. Linux USB 主机控制器(HCD) 驱动6.1 USB 主机控制器驱动初始化6.2 USB 主机控制器设备对象注册和驱动加载7. Linux USB 设备驱…

【亲测搭建成功】模拟无网络情况下安装K8S集群和相关组件

目录标题 前言准备工作:k8s集群:先构思网络拓扑图划分网络资源服务器开始搭建服务器操作系统初始化1.关闭防火墙2. 关闭selinux3. 修改网卡配置5.系统模块配置nacos 高可用mysql双主+双从rockemq 集群nginx高可用(双主)Redis 双主、双从minio分布式文件存储前言 最近项目上…

vulnhub Noob渗透笔记

靶机下载地址:https://www.vulnhub.com/entry/noob-1,746/ kali ip 信息收集 依旧我们先使用nmap扫描确定一下靶机ip nmap -sP 192.168.20.0/24发现靶机ip 扫描开放端口 nmap -A -p 1-65535 192.168.20.129 开放21 80 55077端口 先尝试使用匿名账号登录ftp,账户anonym…

linux系统运维面试题大全(137道题)

linux系统运维面试题大全 1、 如何看当前Linux系统有几颗物理CPU和每颗CPU的核数&#xff1f; 查看物理cup&#xff1a; cat /proc/cpuinfo|grep -c ‘physical id’ 查看每颗cup核数 cat /proc/cpuinfo|grep -c ‘processor’ 2、查看系统负载有两个常用的命令&#xff0c;…

STM32 ADC+定时器+DMA+FFT

本次实现的功能为单片机DAC输出一个正弦波&#xff0c;然后ADC定时采样用DMA输出&#xff0c;最后对DAC输出的波形进行FFT。单片机STM32F103ZET6内部时钟一、配置ADCADC端口为PA1&#xff0c;采用DMA输出&#xff0c;定时器3触发定时器时钟64M&#xff0c;分频后为102.4KHzADC采…

Scrapy的callback进入不了回调方法

一、前言 有的时候&#xff0c;Scrapy的callback方法直接被略过了&#xff0c;不去执行其中的回调方法&#xff0c;可能排查好久都排查不出来&#xff0c;我来教大家集中解决方法。 yield Request(urlurl, callbackself.parse_detail, cb_kwargs{item: item})二、解决方法 1…