数据结构(四)————二叉树和堆(中)

制作不易,三连支持一下呗!!!

文章目录

  • 前言
  • 一、堆的概念及结构
  • 二、堆的实现
  • 三.堆的应用
  • 总结


前言

CSDN 

这篇博客介绍了二叉树中的基本概念和存储结构,接下来我们将运用这些结构来实现二叉树


一、堆的概念及结构

1.概念:

堆是一种完全二叉树,但是堆中每个节点都不大于(或不小于)其父节点,这样的完全二叉树就称为堆。

堆的性质:堆中每个节点都值都不大于(不小于)其父节点的值

                  堆是一种完全二叉树

堆分为大堆和小堆:根节点为最大值的是大堆,根节点为最小值的是小堆。

2.结构:

堆通常采用的是顺序存储的方式,即将数据存储在数组中,通过父节点和孩子节点下标的关系来相连起来。

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

二.堆的实现

1.堆的初始化和销毁

这个部分比较简单,直接放代码

//初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->size = php->capacity = 0;
}//销毁
void HPDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}

2.堆的插入数据(向上调整算法) 

每次插入数据后我们都需要调整数据的位置,以保证满足堆的定义,这里我们写了一个向上调整函数

//向上调整算法
void AdjustUp(HPDateType* a,int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

这里我们建的是小堆,所以判断条件是孩子的值小于父亲的值时就交换。

所以 push数据时,在插入到size位置的基础上,只需要加一个向上调整函数的调用即可。

void HPPush(HP* php, HPDateType x)
{assert(php);if (php->size == php->capacity){int newcapacitty = php->capacity == 0 ? 4 : 2 * php->capacity;HPDateType* tmp = (HPDateType*)realloc(php->a, sizeof(HPDateType)*newcapacitty);if (tmp == NULL){perror("realloc:");return;}php->capacity = newcapacitty;php->a = tmp;}php->a[php->size] = x;php->size++;//向上调整AdjustUp(php->a,php->size-1);
}

下面我们分析一下向上调整算法建堆的时间复杂度: 

	//建堆int i = 0;for(i = 0; i <10; i++){HPPush(&hp, a[i]);}

假设我们要N个节点 ,树的深度是h。

这样我们就可以得到 2^{h-1}<N<=2^{h}-1

反解得\log (N+1)<h<(\log N)+1,近似可得h约等于logN。

因为向上调整最坏情况下会调整高度次,而高度约等于logN,所以向上调整算法的时间复杂度就是logN。

void HPInitArray(HP* php, HPDateType* a, int n)
{assert(php);php->a = (HPDateType*)malloc(sizeof(HPDateType)*n);if (php->a == NULL){perror("Init:");return;}memcpy(php->a, a, n * sizeof(HPDateType));php->capacity = php->size = n;//建堆for (int i=1; i < php->size; i++){AdjustUp(php->a, i);}
}

那么用向上调整算法建堆时,在插入第k层的数据时,最多向上调整k-1次,第k层有2^{k-1}个节点,这些节点共需向上调整(k-1)*2^{k-1}次。

所以时间复杂度o(N)=1*2^{1}+…+(h-1)*2^{h-1}=2^{h}*(h-2)+2

又因为h约等于logN

o(N)=N*(\logN-2)+2。近似为N*logN

3. 删除数据(向下调整算法)

注意:堆删除数据时是删除堆顶的数据,而不是最后一个位置的数据!!!

可能大家首先想到的删除方法是挪动数据向前一个覆盖。

但是这种方法有两个缺陷:

1.这种操作的时间复杂度是o(N),效率不是很高。

2.这种操作完全破坏了之前建立的堆的结构,最后我们还要耗费大量的操作时间来重新建堆。

因此,这里我们采用另一种思路:

先交换最后一个位置和堆顶元素,再size--。这样我们就删除了堆顶数据,并且并没有完全破坏掉堆的结构,因为除堆顶数据外,堆顶元素的左子树和右子树依旧还是堆结构,我们只需要将堆顶元素向下调整,将它放置在合理位置就可以了。

向下调整算法:

//向下调整算法
void AdjustDown(HPDateType* a, int n, int parent)
{int child = parent * 2 + 1;while(child < n){if (child+1 < n && a[child + 1] < a[child]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}else {break;}}
}

 注意:我们依旧以小堆为例,在调整时我们的思路是:和孩子中小的那个值比较,如果孩子比父亲的值要小,就交换,并更新孩子和父亲的值,循环操作,直到终端结点。

向下调整算法的适用条件:下面的节点是堆。

那么我们pop操作就比较简单了。

pop函数:

//删除堆顶数据
void HPPop(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);
}

我们接着分析一下使用向下调整算法建堆的时间复杂度: 

为满足向下调整算法的条件,我们从最后一个节点的父节点开始向下调整。

void HPInitArray(HP* php, HPDateType* a, int n)
{assert(php);php->a = (HPDateType*)malloc(sizeof(HPDateType)*n);if (php->a == NULL){perror("Init:");return;}memcpy(php->a, a, n * sizeof(HPDateType));php->capacity = php->size = n;//向下调整建堆for (int i = (php->size - 1 - 1) / 2; i >= 0; i--){AdjustDown(php->a, php->size, i);}
}

同向上调整算法类似,时间复杂度O(N)=1*2^{h-2} +…+(h-1)*2^{0}=2^{h}-1-h.

由满二叉树h=log(N+1)得O(N)=N-log(N+1)

所以使用向下调整算法建堆的时间复杂度为O(N)=N。

比使用向上调整建堆效率提高了非常多!!!

4.其他一些小函数 

//取堆顶数据
HPDateType HeapTop(HP* php)
{assert(php);return php->a[0];
}
//判断堆是否为空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}

 这两个函数非常简单,有之前顺序表,链表,栈和队列的基础,应该是不难理解的。

三.堆的应用 (堆排序和TopK问题)

1.TopK问题

TopK问题:即求数据结合中前K个最大的元素或最小的元素,一般情况下数据量都比较大。

比如我们要从100亿个数据中找到最大的前十个数是多少。

我们没有了解堆之前可能想法就是:将数据存到一个数组中,用排序算法排序一下,最后取最大的十个数。

但是这样的方法实践中是不可行而且就算可行效率也不高的。

但是根据堆的性质,堆顶的元素就是最大值或最小值。那如果我们要找最大的十个数,我们就建小堆,初始先将所以数据中的前十个元素建成一个小堆,依次遍历数据,如果数据比堆顶元素大就将堆顶元素替换成这个数据,并向下调整,保持小堆的状态。直至结束,最后在小堆中的十个值就是最大的十个数。

时间复杂度O(N)=K+(N-K)*logK。

这里我们采用循环产生随机数的方法来创造大量随机数据来模拟TopK问题。

这样我们就创造了有10000个数据的文件,并且这些数据的大小都在1000000以内。

这时我们手动在10个数据后面补位使它们大小超过1000000,那么如果程序正确,我们最后打印出来的值是10个比1000000大的值。

结果和预期相同,证明我们都程序大概率是没什么问题的。 

 

2.堆排序

如果我们想要将一组数排成升序,我们就建大堆,要排成降序,就排成小堆

void HeapSort(int* a, int n)
{//建堆for (int i = (n - 1 - n) / 2; i >= 0; i--){AdjustDown(a, n, i);}int end = n - 1;while (end>0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;}
}

堆排序的时间复杂度计算时和向上调整建堆一样,都是N*logN,我们忽略最开始建堆(O(N))的消耗。 


总结

这篇博客详细介绍了堆结构的实现和实践中的应用,希望对大家有所收获。

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

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

相关文章

用sunoAI写粤语歌的方法,博主已经亲自实践可行

粤语歌还是很好听的&#xff0c;那么如何使用suno进行粤语歌的创作呢&#xff1f; 本文和大家进行分享下如何进行粤语歌曲的创作。 访问地址如下&#xff08;电脑端/手机端一个地址&#xff09;&#xff1a; ​https://suno3.cn/#/?i8NCBS8_WXTT 在微信浏览器中也可以直接…

css 案例 横向滚动渐变

效果 完整代码&#xff1a; <template><view class"content"><view class"tab"><view class"tab-item" v-for"(item,index) in tab" :key"index" click"handlerTab(index)":class"ind…

winserver系统设置图片查看器

新建 .bat 批处理执行文件&#xff0c;内容如下&#xff1a; echo off&cd&color 0a&cls echo Set Win10 Photo Viewer reg add "HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations" /v ".jpg" /t REG_SZ /d Photo…

MySQL——利用变量进行查询操作

新建链接&#xff0c;自带world数据库&#xff0c;里面自带city表格。 DQL # MySQL利用变量进行查询操作 set cityNameHaarlemmermeer; select * from city where NamecityName;# 多个结果查询 set cityName1Haarlemmermeer; set cityName2Breda; set cityName3Willemstad; s…

古月居讲师/签约作者招募计划

机器人&#xff0c;作为一个集成了多学科技术的复杂系统&#xff0c;其开发过程充满了挑战。为了帮助开发者们更好地克服这些挑战&#xff0c;提升项目的开发效率和质量&#xff0c;古月居特别招募[博客签约作者/课程讲师]。如果您平常热爱记录、分享开发者经验的习惯&#xff…

Emby for Mac(轻松管理多媒体影音库)1.9.9中文版

Emby for Mac是一款强大的多媒体影音库管理工具&#xff0c;可以帮助用户轻松管理和浏览自己的影音资源。它可以将用户的个人视频、音乐和照片组合在一起&#xff0c;并将其流式传输到用户的设备上。 Emby for Mac 1.9.9中文版下载 Emby for Mac具有易于使用的界面&#xff0c;…

机器学习案例:加州房产价格(四)

参考链接&#xff1a;https://hands1ml.apachecn.org/2/#_12 数据探索和可视化、发现规律 通过之前的工作&#xff0c;你只是快速查看了数据&#xff0c;对要处理的数据有了整体了解&#xff0c;现在的目标是更深的探索数据。 首先&#xff0c;保证你将测试集放在了一旁&…

【Docker系列】Linux部署Docker Compose

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

山东济南中国当代文化名人颜廷利:大自然赋予人类众生的真正贵重礼物

大自然赋予了众生---火&#xff08;太阳&#xff0c;万物生长靠太阳&#xff09;、水&#xff08;河流&#xff0c;水是生命之源&#xff09;、木&#xff08;空气&#xff0c;生命就在一翕一合的呼吸之间&#xff09;、土&#xff08;大地&#xff0c;坤为大地之母&#xff0c…

Hive-拉链表的设计与实现

Hive-拉链表的设计与实现 在Hive中&#xff0c;拉链表专门用于解决在数据仓库中数据发生变化如何实现数据存储的问题。 1.数据同步问题 Hive在实际工作中主要用于构建离线数据仓库&#xff0c;定期的从各种数据源中同步采集数据到Hive中&#xff0c;经过分层转换提供数据应用…

【JAVA SE】初识JAVA

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;JAVA 个人主页&#xff1a;Celias blog~ 目录 ​编辑 一、关于JAVA 1.1 JAVA语言简介 1.2 语言优势 1…

链表常见OJ题

目录 题目一&#xff1a;移除链表元素 &#xff08;1&#xff09;题目链接 &#xff08;2&#xff09;题目要求 &#xff08;3&#xff09;题解 题目二&#xff1a;反转链表 &#xff08;1&#xff09;题目链接 &#xff08;2&#xff09;题目要求​编辑 &#xff08;3…

项目9-网页聊天室1(注册+Bycrpt加密)

1.准备工作 1.1.前端页面展示 1.2 数据库的建立 我们通过注册页面&#xff0c;考虑如何设计用户表数据库。 用户id&#xff0c;userId用户名&#xff0c;唯一&#xff0c;username用户密码&#xff0c;password&#xff08;包括密码和确认密码ensurePssword【数据库没有该字段…

【简单介绍下Milvus】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

网络3--网络通信的深度理解(端口号)

网络通信的进一步理解 两个主机间进行通信&#xff0c;其实是两个主机间的软件进行通信&#xff0c;软件也就是可执行程序&#xff0c;运行时就是进程&#xff0c;所以也为进程间通信。 进程间通信需要共享资源&#xff0c;这里两个主机间的共享资源是网络&#xff0c;利用的是…

Visual Studio生成C++的DLL文件(最简单版)

前言 当你在使用C编写一些可重用的代码时&#xff0c;将其打包成一个动态链接库&#xff08;DLL&#xff09;可以使其更容易地被其他项目或者程序调用和使用。Visual Studio提供了一种简单的方式来生成C的DLL文件。下面是一个关于如何在Visual Studio中生成C的DLL文件的简单教…

【 第一性原理计算方法及应用】

第一性原理计算方法及应用述

对接极速行情丨DolphinDB MDL 行情插件使用指南

通联数据依托于金融大数据&#xff0c;结合人工智能技术为投资者提供个性化、智能化、专业化投资服务&#xff0c; MDL 则是通联数据提供的高频行情数据服务。DolphinDB 提供了能够从 MDL 服务器获取高频行情数据的 DolphinDB MDL 插件&#xff0c;帮助用户方便地通过 DolphinD…

算法day06

第一题 1658. 将 x 减到 0 的最小操作数 如题上述&#xff1a; 本题原来的意思给定一个数字x&#xff0c;从数组的左边或者右边 使用x减去数组中的数字&#xff0c;直到减去最后一个数字为0时&#xff0c;返回最小的操作次数&#xff1b;如果最终减去的数组中的数字之后不能得…

HR系统组合漏洞挖掘过程

前言 某天在项目中遇到了一个奇怪的人才管理系统&#xff0c;通过FOFA&#xff08;会员可在社区获取&#xff09;进行了一番搜索&#xff0c;发现了该系统在互联网上的使用情况相当广泛。于是&#xff0c;我开始了后续的审计过程。 在搜索过程中&#xff0c;我偶然间找到了一份…