数据结构之堆

目录

前言

堆的概念与结构

堆的实现

 堆的初始化

堆的销毁

堆的显示

堆的插入

堆的向上调整算法

堆的删除

堆的向下调整算法

堆的判空

获取堆顶元素

 堆的数据个数

堆的创建


前言

二叉树的顺序结构存储即使用数组存储,而数组存储适用于完全二叉树完全二叉树不会存在空间上的浪费二叉树的顺序存储在物理上是一个数组,在逻辑上是一颗二叉树

完全二叉树的顺序存储可以根据下标寻找孩子结点或者父结点,规律如下

leftchild=2*parent+1,   rightchild=2*parent+2;

parent=(child-1)/2 ;

堆的概念与结构

堆的定义:

如果有一个关键码的集合K = {K1 ,K2 ,K3 ,…,Kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <=K2i+1且Ki<=K2i+2(Ki >= K2i+1且Ki >= K2i+2) i = 0,1, 2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆;
堆的性质:
  • 堆中某个节点的值总是不大于或不小于其父节点的值
  • 堆总是一棵完全二叉树
  • 小根堆示意图

  • 大根堆示意图

堆的实现

 堆总是一棵完全二叉树,堆是用数组存储的;

//堆结构的定义
//由于是顺序存储,采用顺序表定义
typedef int HeapDataType;
typedef struct Heap
{HeapDataType* nums;//数组int size;//数据个数int capacity;//记录数组容量
}Heap;

 堆的初始化

//堆的初始化
void HeapInit(Heap* php)
{assert(php != NULL);php->nums = (HeapDataType*)malloc(sizeof(HeapDataType)*4);if (php->nums == NULL){perror("malloc failed:");exit(-1);}php->size = 0;php->capacity = 4;
}

堆的销毁

void HeapDestroy(Heap* php)
{assert(php != NULL);free(php->nums);php->nums = NULL;php->size = 0;php->capacity = 0;
}

堆的显示

//堆的显示
void HeapPrint(Heap* php)
{assert(php != NULL);for (int i = 0; i < php->size; i++){printf("%d ", php->nums[i]);}printf("\n");
}

堆的插入

堆的插入是在堆尾的下一个位置插入数据并保证数组的逻辑结构为堆;

  • case 1:

当在数组尾元素的下一个位置插入的数据其值大于等于父节点的值时,仍然为小堆;

  • case 2:

当在数组尾元素的下一个位置插入的数据其值小于父节点的值时,堆的逻辑结构被破坏,采用向上调整算法,将其调整为堆;

堆的向上调整算法

堆向上调整算法的前提是当插入第k(k>1)数据,前k-1个数据为堆;

由于堆的逻辑结构为小堆,孩子结点处插入的数值小于其父节点处的值,堆的逻辑结构被破坏;首先交换child位置处与parent位置处的值,然后child=parent,parent=(child-1)/2,继续比较孩子节点与父亲结点处的数值,若不满足小堆,继续向上调整,直至根结点的位置为止或出现满足小堆的数值出现停止;

case 1:

case 2:

向上调整算法的时间复杂度

当插入的数据不需要调整,时间复杂度为O(1);

当插入的数据一直调整到根结点处,调整了高度h次,设满二叉树的结点个数为N,则h=log2(N+1),那么其时间复杂度为O(logn);

综上所述,时间复杂度为O(logn);

//交换
void swap(HeapDataType* p1, HeapDataType* p2)
{HeapDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}
//堆的向上调整算法
void AdjustUp(HeapDataType* nums, int child)
{int parent = (child - 1) / 2;while (child>0){if (nums[child] < nums[parent]){swap(&nums[child], &nums[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}
//堆的插入
void HeapPush(Heap* php, HeapDataType x)
{assert(php != NULL);//检查数组容量,容量满时扩容;if (php->size == php->capacity){HeapDataType* tmp = (HeapDataType*)realloc(php->nums, sizeof(HeapDataType)* 2 * (php->capacity));if (tmp == NULL){perror("realloc failed:");exit(-1);}php->nums = tmp;php->capacity = 2 * (php->capacity);}//插入堆的叶结点即二叉树的叶节点php->nums[php->size] = x;php->size++;//任意数据插入之后还是堆吗?//结论是否定的-->向上调整算法-->调整为堆//参数设计为指向数组首元素的指针与数组尾元素的下标,返回值为空AdjustUp(php->nums, php->size - 1);
}

堆的删除

堆的删除是删除堆顶数据,并且保证其逻辑结构仍然为堆,删除的方法是将堆顶的数据与最后一个数据交换,然后删除数组最后一个数据,最后进行向下调整算法,保证其逻辑结构为堆;

堆的向下调整算法

堆向下调整算法的前提左右子树皆为大堆或者左右子树皆为小堆;

首先利用假设法寻找同一高度处值最小的孩子,根据其左右子树为小堆还是大堆,按照小堆或大堆的原则将其交换,若为小堆,父节点处的数值大于孩子结点出的数值,则交换彼此位置;若为大堆,父节点处的数值小于孩子结点出的数值,则交换彼此位置;直至叶节点为止或出现满足其逻辑上大小堆的数值为止;

堆向下调整算法的时间复杂度为O(logN);

//堆的向下调整算法
void AdjustDown(HeapDataType* nums, int n, int parent)
{//假设法求同一深度左右孩子最小的一个,假设左孩子为最小int child = parent * 2 + 1;while (child<n){if (child+1 < n && nums[child] > nums[child + 1]){child++;}//无论左右孩子,child为最小,调整为小堆;if (nums[child] < nums[parent]){swap(&nums[child], &nums[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}
//堆的删除
void HeapPop(Heap* php)
{//删除数组首元素,并且保证逻辑为堆;assert(php != NULL);assert(php->size > 0);swap(&php->nums[0],&php->nums[php->size - 1]);php->size--;//向下调整AdjustDown(php->nums, php->size, 0);
}

堆的判空

//堆的判空
bool HeapEmpty(Heap* php)
{assert(php);return php->size == 0;
}

获取堆顶元素

//取堆顶元素
HeapDataType HeapTop(Heap* php)
{assert(php != NULL);assert(php->size > 0);return php->nums[0];
}

堆的数据个数

//堆的数据个数
int HeapSize(Heap* php)
{assert(php != NULL);return php->size;
}

堆的创建

  • 建堆方案一(向上调整建堆)

给定一个数组,这个数组逻辑上是一颗完全二叉树,而且不一定为堆,通过向上调整算法将其构建为堆;建堆的思想为以数组首元素的下一个位置为起点,利用向上调整算法,依次插入元素建堆

 向上建堆示意图(大堆)

注:向上调整建堆的时间复杂度为O(N*logN);

void HeapCreate(Heap* php, HeapDataType* nums, int n)
{assert(php != NULL);php->nums = (HeapDataType*)malloc(sizeof(HeapDataType)*n);if (php->nums == NULL){perror("malloc fail:");exit(-1);}php->size = php->capacity = n;memcpy(php->nums, nums, sizeof(HeapDataType)*n);//向上调整建堆,建堆的时间复杂度为O(N*logN);for (int i = 1; i<n; i++){AdjustUp(php->nums,i);}
}
  • 建堆方案二(向下调整建堆)

当数据无序存放于数组,数组逻辑上是一颗完全二叉树,而且不一定为堆,以倒数第一个非叶子结点为起点向下建堆,由于对于倒数第一个叶子结点其左右子树只有一个数据,既可以看作大堆,也可以看作小堆向下建堆的前提为其左右子树皆为大堆或者皆为小堆,如此可自底向上调整为堆;

向下建堆示意图(大堆)

 

 上图倒数第一个非叶子结点parent=(child-1)/2; 而child为数组尾元素的下标;上图直至调整到根节点为止;

向下调整建堆的时间复杂度为O(N);

void HeapCreate(Heap* php, HeapDataType* nums, int n)
{assert(php != NULL);php->nums = (HeapDataType*)malloc(sizeof(HeapDataType)*n);if (php->nums == NULL){perror("malloc fail:");exit(-1);}php->size = php->capacity = n;memcpy(php->nums, nums, sizeof(HeapDataType)*n);//向下调整建堆,建堆的时间复杂度为O(N);for (int i = (n-1-1)/2; i>=0; i--){AdjustDown(php->nums, n,i);}
}

Top-K问题

Top-K问题:求取一组数据中前K个最大的元素或者最小的元素
1. 数据集合前K个元素建堆
前K个最大的元素,则建小堆;
前K个最小的元素,则建大堆;

2.剩余的N-K个元素依次与堆顶元素比较,不满足则替换堆顶元素;

假设数组中含有50个数据,取这50个数据中最大的三个

首先前3个元素建堆---->建小堆

 

由于是小堆,根节点处的数值最小(X<Y&&X<Z),当M大于X时,替换X,并且向下调整为小堆,如此当下一次插入数值,循环往复,挑选出前K个最大的数据;

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

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

相关文章

【具身智能综述1】A Survey of Embodied AI: From Simulators to Research Tasks

论文标题&#xff1a;A Survey of Embodied AI: From Simulators to Research Tasks 论文作者&#xff1a;Jiafei Duan, Samson Yu, Hui Li Tan, Hongyuan Zhu, Cheston Tan 论文原文&#xff1a;https://arxiv.org/abs/2103.04918 论文出处&#xff1a;IEEE Transactions on E…

柯桥银泰附近有学德语的地方吗,留学德语培训

01 die Garantiefr jemandem/etwas 给某人或某事的保障 Das System bietet die Garantie fr die Bauer. 02 der Gebrauch von etwas 使用某物 Wir haben den Gebrauch vom Computer gelerbt. 我们学会了使用电脑。 03 Die Geduld mit jemandem/etwas 对..的耐心 Der Lehre…

智慧河湖方案:AI赋能水利水务,构建河湖智能可视化监管大数据平台

一、方案背景 我国江河湖泊众多&#xff0c;水系发达。伴随着经济社会快速发展&#xff0c;水生态水环境问题成为群众最关注的民生议题之一。一些河流开发利用已接近甚至超出水环境承载能力&#xff0c;一些地区废污水排放量居高不下&#xff0c;一些地方侵占河道、围垦湖泊等…

如何在不恢复出厂设置的情况下解锁 Android 手机密码?

如何在不恢复出厂设置的情况下解锁 Android 手机密码&#xff1f; 当您忘记 Android 手机的密码时&#xff0c;可能会有压力&#xff0c;尤其是当您不想恢复出厂设置并删除所有数据时。但是&#xff0c;有一些方法可以在不诉诸如此激烈的步骤的情况下解锁手机。我们将在这篇文…

数据仓库扫盲系列(1):数据仓库诞生原因、基本特点、和数据库的区别

数据仓库的诞生原因 随着互联网的普及&#xff0c;信息技术已经深入到各行各业&#xff0c;并逐步融入到企业的日常运营中。然而&#xff0c;当前企业在信息化建设过程中遇到了一些困境与挑战。 1、历史数据积存。 过去企业的业务系统往往是在较长时间内建设的&#xff0c;很…

JavaSE编程题目练习(三)

博客昵称&#xff1a;架构师Cool 最喜欢的座右铭&#xff1a;一以贯之的努力&#xff0c;不得懈怠的人生。 作者简介&#xff1a;一名Coder&#xff0c;欢迎关注小弟&#xff01; 博主小留言&#xff1a;哈喽&#xff01;各位CSDN的uu们&#xff0c;我是你的小弟Cool&#xff0…

2023.10.20期中考核复现(misc)

杂项题就是2023陇剑杯的题目&#xff0c;可能还是不感兴趣吧&#xff0c;自从打完蓝帽杯之后除了web以外什么都没看 flow analysis 1 题目&#xff1a;What is the backdoor file name that comes with the server?( Including file suffix) 服务器附带的后门文件名是什么&am…

【前端】图片裁剪路径绘制及图片不规则裁剪

说明 项目中可能需要用户根据展示的图片&#xff0c;然后绘制需要裁剪的路径&#xff0c;再根据绘制的坐标进行裁剪&#xff0c;以下是前端的裁剪路径绘制的代码示例&#xff0c;后端可以根据当前的获取到的坐标进行裁剪&#xff0c;裁剪的坐标保存在coordinate数组中。 代码 …

【Maven教程】(八):使用 Nexus 创建私服 ~

Maven 使用 Nexus 创建私服 1️⃣ Nexus简介2️⃣ 安装 Nexus2.1 下载 Nexus2.2 Bundle 方式安装 Nexus2.3 WAR 方式安装 Nexus2.4 登录 Nexus 3️⃣ Nexus 的仓库与仓库组3.1 Nexus 内置的仓库3.2 Nexus 仓库分类的概念3.3 创建 Nexus 宿主仓库3.4 创建 Nexus 代理仓库3.5 创…

计算机毕业设计 基于SpringBoot笔记记录分享网站的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

openGauss学习笔记-105 openGauss 数据库管理-管理用户及权限-默认权限机制

文章目录 openGauss学习笔记-105 openGauss 数据库管理-管理用户及权限-默认权限机制 openGauss学习笔记-105 openGauss 数据库管理-管理用户及权限-默认权限机制 数据库对象创建后&#xff0c;进行对象创建的用户就是该对象的所有者。openGauss安装后的默认情况下&#xff0c…

C++算法前缀和的应用:分割数组的最大值的原理、源码及测试用例

分割数组的最大值 相关知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例&#xff1a;付视频课程 二分 过些天整理基础知识 题目 给定一个非负整数数组 nums 和一个整数 m &#xff0c;你需要将这个数组分成 m 个非空的连续子数组。 设计一个算法…

聊聊分布式架构09——分布式中的一致性协议

目录 01从集中式到分布式 系统特点 集中式特点 分布式特点 事务处理差异 02一致性协议与Paxos算法 2PC&#xff08;Two-Phase Commit&#xff09; 阶段一&#xff1a;提交事务请求 阶段二&#xff1a;执行事务提交 优缺点 3PC&#xff08;Three-Phase Commit&#x…

11-k8s-service网络

文章目录 一、网络相关资源介绍二、开启ipvs三、nginx网络示例四、pod之间的访问示例五、service反向代理示例 一、网络相关资源介绍 Servcie介绍 Service是对一组提供相同功能的Pods的抽象&#xff0c;并为它们提供一个统一的入口。借助Service&#xff0c;应用可以方便的实现…

如何在电脑上设置新的蓝牙耳机

本文介绍如何将蓝牙耳机连接到Windows或Mac电脑。 如何在Windows上设置新的蓝牙耳机 蓝牙耳机的设置过程因平台而异&#xff0c;但以下是Windows 11的步骤&#xff1a; 1、选择“开始”&#xff0c;然后在搜索框中输入蓝牙&#xff0c;以显示蓝牙和其他设备。 2、选择添加设…

【马蹄集】—— 概率论专题:第二类斯特林数

概率论专题&#xff1a;第二类斯特林数 目录 MT2224 矩阵乘法MT2231 越狱MT2232 找朋友MT2233 盒子与球MT2234 点餐 MT2224 矩阵乘法 难度&#xff1a;黄金    时间限制&#xff1a;5秒    占用内存&#xff1a;128M 题目描述 输入两个矩阵&#xff0c;第一个矩阵尺寸为 l…

2024年仁爱学院专升本招生专业对应范围专业目录更新的通知

天津仁爱学院2024年高职升本科招生专业对应范围专业目录 为了更好的进行天津仁爱学院专升本工作&#xff0c;动画专业不分文理进行录取。为了进一步提升录取专业的培养需要&#xff0c;请同学们复习专业课时加强专业课学习&#xff0c;请同学们在报考时关注天津仁爱学院招生章…

Unreal Engine 4 + miniconda + Python2.7 + Pycharm

1.​首先启用UE4插件里的Python Scripting插件 ​ 2. 在UE4项目设置中 开启Python开发者模式 生成unreal.py文件&#xff0c;用于在Pychram中引入Unreal PythonAPI 生成的unreal.py 在&#xff1a; "项目路径\Intermediate\PythonStub\unreal.py"3. 安装Miniconda…

关于opencv的contourArea计算方法

cv::contourArea计算的轮廓面积并不等于轮廓点计数&#xff0c;原因是cv::contourArea是基于Green公式计算 老外的讨论 github 举一个直观的例子&#xff0c;图中有7个像素&#xff0c;橙色为轮廓点连线&#xff0c;按照contourArea的定义&#xff0c;轮廓的面积为橙色所包围…

Visual Studio Code官网下载、vscode下载很慢、vscode下载不了 解决方案

前言 开发界的小伙伴们对于Visual Studio Code开发环境来可以说非常熟悉了&#xff0c;但由于在Visual Studio Code官网的下载速度非常的慢&#xff0c;即便开了代理也是一样的很慢、甚至下载被中断&#xff0c;几乎不能下载。 解决方案 1、在Web浏览器上打开vscode官网&#…