【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

  • 一、前言:二叉树的顺序结构
  • 二、堆的概念及结构
  • 三、堆的实现(本篇博客以实现小堆为例
    • 3.1 准备工作
    • 3.2 初始化
    • 3.3 堆的插入
      • 3.3.1 向上调整算法
    • 3.4 堆的删除
      • 3.4.1 向下调整算法
    • 3.5 堆的判空(<font color=orange>接下的过于简单直接给出带啊吗)
    • 3.6 取堆顶的数据
    • 3.7 堆的个数
    • 3.8 堆的销毁
  • 四、所有代码


在这里插入图片描述


一、前言:二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。
 
现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

在这里插入图片描述


二、堆的概念及结构

堆是一种特殊的数据结构,可以将堆分为大顶堆和小顶堆两种形式。堆中的每个节点都有一个值,并且满足以下两个条件:
 
①:堆的父节点的值总是大于或等于其子节点的值(大顶堆)或者小于或等于其子节点的值(小顶堆)。
②:堆是完全二叉树,即除了最底层外,其他层的节点都是满的,并且最底层的节点都尽量靠左排列。

大(小)堆示意图:

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


三、堆的实现(本篇博客以实现小堆为例

3.1 准备工作

由于堆是通过数组来实现的,所以我们也和顺序表一样,首先要创建一个结构体来存储:数组指针 + 容量 + 存储数据大小

代码实现:

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;//数组指针int size;//存储数据大小int capacity;//容量
}HP;

3.2 初始化

初始化有两种方式:
①:初始化时为数组开辟一定大小空间。②:直接将数组指针置为NULL,插入数据过程中在进一步处理。(本篇博客采用第二种)

代码实现:

void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = 0;php->size = 0;
}

3.3 堆的插入

【代码思路】:
①:在插入数据前,我们首先要判断是否要扩容的问题。由于前面初始化时我们直接置空,所以我们先判断容量是否为空。如果为空开4个空间,否则空间扩大到原来的2倍。(为空时,第一次具体开辟多少空间读者可自行选择,本篇博客开4)
②:接下来就是插入数据了!但有一个问题,直接插入数据可能会破坏堆的结构,所以我们采用了向上调整算法

代码:

void HPPush(HP* php, HPDataType x)
{assert(php);//扩容if (php->size == php->capacity){int newcapacity = php->size == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a,sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("malloc fail");exit(-1);}php->a = tmp;php->capacity = newcapacity;}//插入数据php->a[php->size] = x;php->size++;//向上调整AdjustUp(php->a, php->size - 1);
}

3.3.1 向上调整算法

【代码思路】:由于插入数据时,影响的只是插入数据到根节点间的关系。所以我们只需将插入数据通过双亲节点调到合适位置即可
 
Tips:父节点和子节点关系

  • leftchild = parent *2 + 1
  • rightchild = parent * 2 + 2
  • parent = (child - 1)/2

在这里插入图片描述
代码:

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{assert(a);int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent])//小堆{Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}		}
}

3.4 堆的删除

【代码思路】:堆的删除默认是头删。删除有两种思路:
 
①:将根节点删除,再将其余数据全部向前移动。但这样做会造成一个问题:挪动覆盖导致父子节点的关系全乱了,需要重新建堆。为了删个数据,重新建堆,得不偿失,所以我们采用下面这种方法。
 
②:将堆顶的1数据和最后一个数据交换,在删除最后一个数据。堆顶数据在通过向下调整算法调到合适位置即可

在这里插入图片描述

代码:

void HPPop(HP* php)
{assert(php);assert(!HPEmpty(php));//非空,还有数据可删。该接口后面实现Swap(&php->a[0], &php->a[php->size - 1]);//交换php->size--;//删除//向下调整AdjustDown(php->a, php->size, 0);
}

3.4.1 向下调整算法

【代码思路】:向下调整算法有一个前提:左右子树必须是一个堆,才能调整。同时还要注意是调大堆还是小堆。
调小堆:堆顶元素和孩子中最小的节点比较,如果父节点大于较小的子节点子,两者交换。不断向下调整到合适位置。(调大堆,和较大孩子比较)

在这里插入图片描述

代码

void AdjustDown(HPDataType* a, int n, int parent)
{assert(a);int child = parent * 2 + 1;//假设左孩子更小while (child < n){//如果有孩子存在,且有孩子更小,则左孩子加1移到右孩子if ((child + 1) < n && a[child] > a[child + 1]){child++;}if (a[parent] > a[child])//交换{Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{//父节点小于较小的子节点,说明已经调到合适位置,此时break跳出break;}}
}

3.5 堆的判空(接下的过于简单直接给出带啊吗)

bool HPEmpty(HP* php)
{return php->size == 0;
}

3.6 取堆顶的数据

	assert(php);assert(!HPEmpty(php));//断言堆中还有元素return php->a[0];

3.7 堆的个数

int HPSize(HP* php)
{assert(php);return php->size;
}

3.8 堆的销毁

void HPDestory(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}

四、所有代码

Heap.h

#pragma once#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HPInit(HP* php);//初始化
void HPPush(HP* php, HPDataType x);//插入数据
void HPPop(HP* php);//删除数据
int HPTop(HP* php);//堆顶元素
bool HPEmpty(HP* php);//判空
int HPSize(HP* php);//数据个数
void HPDestory(HP* php);//销毁

Heap.c

#include "Heap.h"void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = 0;php->size = 0;
}void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{assert(a);int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent])//小堆{Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}void AdjustDown(HPDataType* a, int n, int parent)
{assert(a);int child = parent * 2 + 1;while (child < n){if ((child + 1) < n && a[child] > a[child + 1]){child++;}if (a[parent] > a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HPPush(HP* php, HPDataType x)
{assert(php);//扩容if (php->size == php->capacity){int newcapacity = php->size == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a,sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("malloc fail");exit(-1);}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;//向上调整AdjustUp(php->a, php->size - 1);
}bool HPEmpty(HP* php)
{return php->size == 0;
}void HPPop(HP* php)
{assert(php);assert(!HPEmpty(php));Swap(&php->a[0], &php->a[php->size - 1]);php->size--;//向下调整AdjustDown(php->a, php->size, 0);
}int HPTop(HP* php)
{assert(php);assert(!HPEmpty(php));return php->a[0];
}int HPSize(HP* php)
{assert(php);return php->size;
}void HPDestory(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}

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

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

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

相关文章

微服务中间件--分布式事务

分布式事务 a.理论基础1) CAP定理2) BASE理论 b.Seata1) XA模式1.a) 实现XA模式 2) AT模式3) TCC模式3.a) 代码实现 4) Saga模式5) 四种模式对比6) TC的异地多机房容灾架构 a.理论基础 1) CAP定理 分布式系统有三个指标&#xff1a; Consistency&#xff08;一致性&#xff…

opencv-人脸关键点定位

#导入工具包 from collections import OrderedDict import numpy as np import argparse import dlib import cv2#https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/ #http://dlib.net/files/# 参数 ap argparse.ArgumentParser() ap.add_argument("-p&quo…

【Java】常见面试题:HTTP/HTTPS、Servlet、Cookie、Linux和JVM

文章目录 1. 抓包工具&#xff08;了解&#xff09;2. 【经典面试题】GET和POST的区别&#xff1a;3. URL中不是也有这个服务器主机的IP和端口吗&#xff0c;为啥还要搞个Host&#xff1f;4. 补充5. HTTP响应状态码6. 总结HTTPS工作过程&#xff08;经典面试题&#xff09;7. H…

vue3 清空/重置reactive

序&#xff1a; 1、适用场景&#xff1a;表单切换验证如下图。 我举个例子&#xff0c;如果下拉选银行卡&#xff0c;提交表单的时候所属银行是要必填验证&#xff0c;但是如果选支付宝&#xff0c;那所属银行就非必填了&#xff0c;然而很多时候from的rules是以props来传的&a…

飞书小程序开发

1.tt.showModal后跳转页面 跳转路径要为绝对路径&#xff0c;相对路径跳转无响应。 2.手机息屏后将不再进入onload()生命周期&#xff0c;直接进入onshow()生命周期。 onLoad()在页面初始化的时候触发&#xff0c;一个页面只调用一次。 onShow()在切入前台时就会触发&#x…

springBoot 配置文件 jpa 相关参数的作用

在Spring Boot应用中&#xff0c;可以通过配置文件来配置JPA&#xff08;Java Persistence API&#xff09;相关的参数。下面是一些常用的JPA配置参数及其作用&#xff1a; spring.jpa.database: 指定JPA使用的数据库类型&#xff0c;默认为自动检测。可选值有HSQL、H2、DERBY…

开放网关架构演进

作者&#xff1a;庄文弘&#xff08;弘智&#xff09; 淘宝开放平台是阿里与外部生态互联互通的重要开放途径&#xff0c;通过开放的产品技术把阿里经济体一系列基础服务&#xff0c;像水、电、煤一样输送给我们的商家、开发者、社区媒体以及其他合作伙伴&#xff0c;推动行业的…

企业网三层架构实验

一、实验拓扑 二、实验要求 1、内网IP地址172.16.0.0/16合理分配&#xff1b; 2、SW1/2之间互为备份&#xff1b; 3、VRRP/STP/VLAN/TRUNK均使用&#xff1b; 4、所有PC通过DHCP获取IP地址&#xff1b; 三、实验思路 1、配置ISP的IP地址&#xff1b; 2、配置R1的IP地址&…

<指针进阶>指针数组和数组指针傻傻分不清?

✨Blog&#xff1a;&#x1f970;不会敲代码的小张:)&#x1f970; &#x1f251;推荐专栏&#xff1a;C语言&#x1f92a;、Cpp&#x1f636;‍&#x1f32b;️、数据结构初阶&#x1f480; &#x1f4bd;座右铭&#xff1a;“記住&#xff0c;每一天都是一個新的開始&#x1…

Mac发现有的软件不能上网的破解之法

1、Mac上打开终端 terminal &#xff0c;获取 root 权限。 sudo -i 2、编辑 hosts 文件 vim /private/etc/hosts 3、找到被禁止软件的数据请求域名&#xff0c;然后删除相关行&#xff0c;快捷件dd&#xff0c;然后:wq保存退出 比如百度 127.0.0.1 pan.baidu.com ##sec 印…

深入完整的带你了解java对象的比较

目录 元素的比较 1.基本类型的比较 2.对象比较的问题 1.运行结果 2.疑问 3.原因 对象的比较 1.覆写基类的equals 2.基于Comparble接口类的比较 3.基于比较器比较 4.三种方式对比 元素的比较 1.基本类型的比较 在Java 中&#xff0c;基本类型的对象可以直接比较大…

LVS-DR模式以及其中ARP问题

目录 LVS_DR LVS_DR数据包流向分析 LVS-DR中ARP问题 问题一 问题二 解决ARP的两个问题的设置方法 LVS-DR特点 LVS-DR优缺点 优点 缺点 LVS-DR集群构建 1.配置负载调度器 2.部署共享存储 3.配置节点服务器 4.测试 LVS 群集 LVS_DR LVS_DR数据包流向分析 客户端…

JVM基础了解

JVM 是java虚拟机。 作用&#xff1a;运行并管理java源码文件锁生成的Class文件&#xff1b;在不同的操作系统上安装不同的JVM&#xff0c;从而实现了跨平台的保证。一般在安装完JDK或者JRE之后&#xff0c;其中就已经内置了JVM&#xff0c;只需要将Class文件交给JVM即可 写好的…

爬虫工作中代理失效了怎么处理?

Hey&#xff01;亲爱的爬虫小伙伴们&#xff0c;是不是经常在爬虫的工作中遇到代理IP失效的问题&#xff1f;别着急&#xff0c;今天我来分享一些应对代理失效的妙招&#xff01;这些方法简单易行&#xff0c;让你爬虫顺利进行. 一、为什么代理会失效&#xff1f; 在爬虫过程…

vue3+ts+vite项目页面初始化loading加载效果

简介 一分钟实现 vue-pure-admin 同款项目加载时的 loading 效果 一、先看效果 1.1 静态效果 1.2 动态效果 二、上代码 核心代码在body里面&#xff0c;代码中已标明。找到你项目的 index.html &#xff0c;复制粘贴进去即可 <!DOCTYPE html> <html lang"en…

每天一道leetcode:1306. 跳跃游戏 III(图论中等广度优先遍历)

今日份题目&#xff1a; 这里有一个非负整数数组 arr&#xff0c;你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时&#xff0c;你可以跳到 i arr[i] 或者 i - arr[i]。 请你判断自己是否能够跳到对应元素值为 0 的 **任一** 下标处。 注意&#xff0c;不管是什…

spring依赖注入详解(上)

一、Bean销毁的过程 如果bean销毁时会执行的场景 1、设置DestroyMethodName为(inferred) // 先把DestroyMethodName设置为(inferred) Component public class TestBeanPostProcessor implements MergedBeanDefinitionPostProcessor {Overridepublic void postProcessMergedBe…

根据Dockerfile创建容器案例讲解

-f为dokerfile的路径&#xff0c; -t为新镜像的名称及版本。 后面这个点是寻址路径。

阿里面试官常问的TCP和UDP,你真的弄懂了吗?

♥ 前 言 作为软件测试&#xff0c;大家都知道一些常用的网络协议是我们必须要了解和掌握的&#xff0c;面试的时候面试官也非常喜欢问一些协议相关的问题&#xff0c;其中有两个协议因为非常基础&#xff0c;出现的频率非常之高&#xff0c;分别是 ”TCP 协议“ 和 ”UDP 协…

漏洞指北-VulFocus靶场专栏-中级03

漏洞指北-VulFocus靶场专栏-初级03 中级009 &#x1f338;gxlcms-cve_2018_14685&#x1f338;step1&#xff1a;安装系统 密码rootstep2 进入后台页面 账号密码&#xff1a;admin amdin888step3 查看详细 有phpinfo() 中级010 &#x1f338;dedecms-cnvd_2018_01221&#x1f3…