【数据结构】堆的实现

目录

  • 1. 前言
  • 2. 堆的实现
    • 2.1 初始化
    • 2.2 插入
      • 2.2.1 分析
        • 2.2.1.1 情况一
        • 2.2.1.2 情况二
        • 2.2.1.3 情况三
      • 2.2.2 插入代码实现
        • 2.2.2.1 向上调整代码
    • 2.3 删除
      • 2.3.1 分析
      • 2.3.2 删除代码实现
        • 2.3.2.1 向下调整代码
    • 2.4 找根节点数据
    • 2.5 元素个数
    • 2.6 判空
    • 2.7 销毁
  • 3. 源代码
    • 3.1 Heap.h
    • 3.2 Heap.c
    • 3.3 test.c

1. 前言

在上一篇关于树和二叉树的博客中,最后提到了堆。有小根堆和大根堆。
在这里插入图片描述
左边的结构是我们想象出来的,右边才是实际存储的结构。
这次来实现堆。

2. 堆的实现

用数组来实现,这里以实现小堆为例子,它的特点是父节点小于子节点。
先定义一个堆的结构体:为了方便扩容,加了size。

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;

2.1 初始化

刚开始数组中没有数据,置为NILL,此时的size和capacity都为0。
代码实现:

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

2.2 插入

2.2.1 分析

2.2.1.1 情况一

在这里插入图片描述
假设插入的数据为30。
那么堆需要处理吗?
在小堆中父亲节点小于子节点。
通过当前位置,计算父节点的下标来判断一下,是否需要调整,显然28是小于30的这里就不需要调整了。

2.2.1.2 情况二

来看看其它情况:
在这里插入图片描述
这里的子节点就小于父节点,这里就要将父节点和子节点交换一下,然后再判断。
在这里插入图片描述
通过下标将两个位置的值交换之后,分析已经是小根堆了,就不继续往前走了。

2.2.1.3 情况三

在这里插入图片描述
这里先将10与它的父节点28比较,发现10比较小,此时就交换它们两个;再往上看,发现18比10小,又交换;再往上,发现15也比10小,此时又交换。
此时就是这样:
在这里插入图片描述
这个过程叫做向上调整。
只要发现父节点小于子节点时就停止向上调整。

2.2.2 插入代码实现

先判断空间是否足够,不够就扩容,够就直接插入x,再将php->size++

void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}
2.2.2.1 向上调整代码

从child的位置开始调整,就是刚插入的值,也就是size-1
先和它的父节点比较,如果小于父节点就交换。这里直接写成while循环,交换之后向上走,将child 的位置给parent,然后parent = (child - 1) / 2,一直向上走,当child=0时结束或者parent >= 0时结束。

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

在这里插入图片描述

2.3 删除

规定删除堆顶数据。

2.3.1 分析

在这里插入图片描述
这时删除堆顶的数据,那么堆顶就是次小的值。
这里要保持删除之后还是小堆。

如果使用挪动数据覆盖,删除根,此时整棵树的父子关系全乱了,大小关系也乱了,这样是不可行的。

使用首尾交换,然后尾删。
在这里插入图片描述
尾删之后,左右子树依旧是小堆。
在这里插入图片描述
把30换上去就结束了吗?
当然不是,使用向下调整算法。
此时不是小堆,就要调整。
与30子节点18比较,18小,它们两个就交换。再向下,25比18小,又交换一次,再向下,27小于30,又交换。最后到叶子节点就结束。
在这里插入图片描述

2.3.2 删除代码实现

首尾交换删除,然后将php->size--,最后向下调整。

void HeapPop(HP* php)
{assert(php);assert(php->size > 0);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}

删三次
在这里插入图片描述

2.3.2.1 向下调整代码

当父节点大于子节点时就交换一下,然后继续向下判断大小关系。
这里如果定义左右孩子,左孩子小是一种逻辑,右孩子小也是一种逻辑,就很麻烦。
这里使用一个假设法,就直接定义一个孩子。
假设左孩子小,如果解设错了,更新一下,换到右孩子。
如果孩子小于父亲就交换,然后向下走让parent = childchild = parent * 2 + 1

void AdjustDown(int* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){// 假设左孩子小,如果解设错了,更新一下if (child + 1 < size && a[child + 1] < a[child]){++child;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

2.4 找根节点数据

堆顶数据在数组中的位置就是php->a[0]

HPDataType HeapTop(HP* php)
{assert(php);assert(php->size > 0);return php->a[0];
}

2.5 元素个数

元素的个数就是这个数组的长度,直接返回php->size

size_t HeapSize(HP* php)
{assert(php);return php->size;
}

2.6 判空

直接判断一下数组中是否有数据就行,如果php->size == 0为真就是空,为假就不是。

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

2.7 销毁

先断言一下,然后将数组free,再将php->a 置为NULL,最后将php->sizephp->capacity 置为0。

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

3. 源代码

3.1 Heap.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php);
void HeapDestroy(HP* php);
void HeapPush(HP* php, HPDataType x);
// 规定删除堆顶(根节点)
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
size_t HeapSize(HP* php);
bool HeapEmpty(HP* php);

3.2 Heap.c

#include"Heap.h"// 小堆
void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (parent >= 0)while (child > 0){if (a[child] < a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;//child = (child - 1) / 2;//parent = (parent - 1) / 2;}else{break;}}
}// O(logN)
void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}void AdjustDown(int* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){// 假设左孩子小,如果解设错了,更新一下if (child + 1 < size && a[child + 1] < a[child]){++child;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapPop(HP* php)
{assert(php);assert(php->size > 0);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}HPDataType HeapTop(HP* php)
{assert(php);assert(php->size > 0);return php->a[0];
}size_t HeapSize(HP* php)
{assert(php);return php->size;
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

3.3 test.c

#include"Heap.h"int main()
{int a[] = { 4,6,2,1,5,8,2,9};HP hp;HeapInit(&hp);for (int i = 0; i < sizeof(a) / sizeof(int); ++i){HeapPush(&hp, a[i]);}/*int k = 3;while (k--){printf("%d\n", HeapTop(&hp));HeapPop(&hp);}*/while (!HeapEmpty(&hp)){printf("%d ", HeapTop(&hp));HeapPop(&hp);}printf("\n");return 0;
}

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

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

相关文章

许战海战略文库|主品牌升级为产业技术品牌,引领企业全球化发展

在当今高速发展的全球经济中&#xff0c;企业品牌已经成为其核心资产之一。这不仅仅是因为品牌可以为消费者带来识别度&#xff0c;更重要的是&#xff0c;它们可以为企业带来深厚的竞争壁垒。但对于许多企业来说&#xff0c;特别是技术密集型企业&#xff0c;仅仅依靠主品牌的…

如何让消费者接受品牌,口碑营销怎么做?

当新品牌进入小红书时&#xff0c;如何进行口碑营销是一个重要的问题。很多新品牌在刚刚进入小红书时&#xff0c;对于一些敏感时机把握的不准其实本质上&#xff0c;就是不明白什么阶段该做什么事。今天分享的就是如何让消费者接受品牌&#xff0c;口碑营销怎么做&#xff1f;…

电量计驱动代码

外部电量计驱动代码,直接上代码了,懒,不做细节分析。。。。。 /** Fuelgauge battery driver** This package is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Soft…

vue3使用高德地图获取经纬度

首先 安装依赖 cnpm i amap/amap-jsapi-loader --save <script setup> import { onMounted, reactive, ref } from vue import AMapLoader from amap/amap-jsapi-loaderconst map ref(null) const mapData reactive({map: {},keyword: ,selectedLocation: {},selecte…

python object类型

# object类是所有类的父类 # type是所有类的类型&#xff0c;也就是所有类都是由type实例化而来&#xff0c;包括type类和父类object # class 继承object 同时又type类实例化。其中type就是元类print(type的父类,type.__base__) class test:pass print(class的父类是&#xff1…

NX二次开发UF_CURVE_ask_spline_data 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_spline_data Defined in: uf_curve.h int UF_CURVE_ask_spline_data(tag_t spline_tag, UF_CURVE_spline_p_t spline_data ) overview 概述 Reads the spline data a…

Java核心知识点整理大全18-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

抖音小店怎么做?新手应该怎么运营?实操经验分享!

我是电商珠珠 抖音小店的热度一天天在攀升&#xff0c;很多新手小白都会跑来问我&#xff0c;想做抖音小店具体要怎么做。 接下来&#xff0c;我从头到尾的跟大家讲一遍&#xff0c;注意重点。 第一&#xff0c;入驻 入驻的时候需要准备一张营业执照&#xff0c;对于新手来…

Map<Object>, List<Object>>返回满足条件的数据

Map<Object>, List<Object>>返回满足条件的数据 当一个表查询多次时&#xff0c;为了减少数据库的查询操作&#xff0c;可以使用stream流来进行条件筛选&#xff0c;获取所需要的数据。 例&#xff1a; Map<Long, List<PurchaseOrder>> orderMap…

Linux驱动开发——网络设备驱动(理论篇)

目录 一、前言 二、网络层次结构 三、网络设备驱动核心数据结构和函数 一、前言 网络设备驱动是 Linux 的第三大类驱动&#xff0c;也是我们学习的最后一类 Linux 驱动。这里我们首先简单学习一下网络协议层次结构&#xff0c;然后简单讨论 Linux 内核中网络实现的层次结构。…

接口测试工具(Jmeter)必学技巧

安装 使用JMeter的前提需要安装JDK&#xff0c;需要JDK1.7以上版本目前在用的是JMeter5.2版本&#xff0c;大家可自行下载解压使用 运行 进入解压路径如E: \apache-jmeter-5.2\bin&#xff0c;双击jmeter.bat启动运行 启动后默认为英文版本&#xff0c;可通过Options – Cho…

m3u8及其应用

m3u8与协程 HLS找m3u8AES加、解密实例 HLS 即HTTP Live Streaming&#xff0c;将流媒体切分为若干TS片段&#xff0c;通过一个M3U8列表文件将TS片段批量下载实时流式播放。 #EXTM3U:第一行tag标识。#EXT-X-VERSION:版本#EXT-X-TARGETDURATION:定义每个TS的【最大】duration&a…

【知网稳定检索】2024年应用经济学,管理科学与社会发展国际学术会议(AEMSS 2024)

2024年应用经济学&#xff0c;管理科学与社会发展国际学术会议&#xff08;AEMSS 2024&#xff09; 2024 International Conference on Applied Economics, Management Science and Social Development 2024年应用经济学&#xff0c;管理科学与社会发展国际学术会议&#xff…

C++ 协程

经典协程辅助入门代码&#xff1a; typedef cotask::task my_task_t; int main() { // create a task using factory function [with lambda expression] my_task_t::ptr_t task my_task_t::create([]() { //创建协程 std::cout ()->get_id() cotask::this_task::get…

uniapp在H5端实现PDF和视频的上传、预览、下载

上传 上传页面 <u-form-item :label"(form.ququ3 1 ? 参培 : form.ququ3 2 ? 授课 : ) 证明材料" prop"ququ6" required><u-button click"upload" slot"right" type"primary" icon"arrow-upward" t…

流媒体播放器EasyPlayer播放H.265与H.264时进度条样式异常该如何解决?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…

网易云音乐7天黑胶VIP会员免费领取入口怎么领取网易云音乐黑胶VIP7天会员?

网易云音乐7天黑胶VIP会员免费领取入口怎么领取网易云音乐黑胶VIP7天会员&#xff1f; 1、百度搜索「词令」&#xff0c;在搜索框内输入词令「vip163」关键词直达口令&#xff0c;进入网易云音乐7天黑胶VIP会员免费领取入口&#xff1b; 2、输入网易云音乐黑胶VIP7天会员领取词…

AJAX技术-04-- 跨域说明

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1 同源策略同源策略介绍规定要求 请求协议://域名:端口号 关于同源策略练习关于同源策略总结 2.JSONPJSONP原理说明关于JSONP优化 3.CORS介绍介绍不允许跨域说明跨域…

Cascader 级联选择器动态加载数据的回显

如果后端没有只返回第三级的id,而是同时把第三级的名字一起返回了&#xff0c;那么就可以通过下面的方法来实现 1.在级联选择器里面加上这句代码 placeholder"请选择" 2.注册一个字符串 pleasett:"" 3.赋值 如过后端返回的有第三级的选项名 直接进行赋…

itBuilder支持AI对话方式设计表结构啦

更新提示 在老版的AI中不能对话&#xff0c;当AI对需求理解的不准确、不全面时&#xff0c;本次带来的更新针对这个缺陷&#xff0c;提供了再次和AI交互的功能&#xff0c;可以基于之前的设计结果进行修正&#xff0c;详情请点击视频查看。 vedio