当前位置: 首页 > news >正文

堆【数据结构C语言版】【 详解】

目录-笔记整理

  • 一、思考
  • 二、堆概念与性质
  • 三、堆的构建、删除、添加
    • 1. 构建
    • 2. 删除
    • 3. 添加
  • 四、复杂度分析
    • 4.1 时间复杂度
    • 4.2 空间复杂度
  • 五、总结

一、思考

设计一种数据结构,来存放整数,要求三个接口:
1)获取序列中的最值(最大或最小)
2)添加元素
3)删除最值(最大或最小)

分析:

1)如果使用无序的线性表来实现,则需要发现获取最值、删除最值都需要遍历全部数据,复杂度为O(n)
2)如果使用有序的线性表,则查找并删除最值是虽是O(1)级别,但插入一个元素要重新进行排序,最好情况也是O(n)
3)如果平衡二叉查找树实现,虽然查找、插入、删除复杂度是O(log<sub>2</sub>n)级别,但其实现程度复杂,功能多,对于仅实现三个接口来说是”大炮打蚊子“,得不尝失。而使用”堆“能很好实现三种接口,且时间复杂度较低,获取最大值O(1),添加、删除都为O(log<sub>2</sub>n)

(注:这里的堆不是内存模型里的”堆空间“,勿要混淆)

二、堆概念与性质

堆(Heap)是一种数据结构,物理存储采用顺序表,其元素必须满足的性质是:
{ k i ≤ k 2 i + 1 k i ≤ k 2 i 或 { k i ≥ k 2 i + 1 k i ≥ k 2 i \lbrace^{k_i \leq k_{2i}}_{k_i \leq k_{2i+1}} 或 \lbrace^{k_i \geq k_{2i}}_{k_i \geq k_{2i+1}} {kik2i+1kik2i{kik2i+1kik2i
我们称前者为小顶堆(或小根堆),后者为大顶堆(或大根堆)。观察发现,这和完全二叉树的性质5很一样,因此可以逻辑上理解堆为一棵完全二叉树。
例如:序列(5,7,6,9,8,10)满足小根堆的性质在这里插入图片描述
这棵完全二叉树的根元素又叫堆顶元素,也是序列中的最小值,因此,每次查找最小值只需要获取堆顶元素即可,添加一个元素后,需要对堆重新进行调整每个元素满足堆性质,成为一个新堆;删除元素就是堆顶元素出堆,然后重新调整元素位置,直到全部元素满足堆性质,成为一个新堆。

三、堆的构建、删除、添加

1. 构建

(以小顶堆为例)
如何使一个序列变成满足堆性质的序列,并且具有添加、删除、获取最值三大接口?需要思考两个问题
1)如何由该混乱的序列构建一个堆?
2)往堆里添加、删除(删除堆顶)元素后,如何调整剩余元素成为一个新的堆?

已知一个混乱序列(10,8,6,9,7,5),和一个空堆H,然后遍历序列,每遍历一个序列往空堆添加元素,既要考虑每个元素满足堆的性质,又要思考新添加的元素位置(放在 i i i的位置还是 i + 1 i+1 i+1的位置),发现这种代码逻辑很难实现。由堆的性质和完全二叉树的性质类似,把已知的混乱序列逻辑上形象的看成一个完全二叉树。那么问题就转化为如何把一个”混乱“的完全二叉树转变为一棵小根堆对于的完全二叉树
在这里插入图片描述

观察图发现,我们只需要从非叶子 ⌊ n / 2 ⌋ \lfloor n/2\rfloor n/2结点开始,以它为根,对其根以及根的所有后代元素进行调整使其成为一棵小根堆,直到 ⌊ n / 2 ⌋ − 1 \lfloor n/2\rfloor-1 n/21 ~ 1 1 1位置为根元素都调整完毕,构建堆完成。
如何调整?
在这里插入图片描述
(注:假设现在有一个小根堆序列,其对应的完全二叉树如上图所示)
1)堆顶元素输出或出堆,让表尾元素(11)覆盖(5)并删除表尾元素
2)根(11)和其左右孩子(7,6)中最小的比较,发现6比11小,则6和11交换位置,这时以11为根的子树继续调整,10比11小,则互换位置…直到叶子结点(若中途发现根比孩子中最小的还小,则操作结束,该棵子树已经调整好了)
知道了如何调整,那么堆的构建就是从非叶子 ⌊ n / 2 ⌋ \lfloor n/2\rfloor n/2结点为根的树进行调整,直到 ⌊ n / 2 ⌋ − 1 \lfloor n/2\rfloor-1 n/21 ~ 1 1 1位置为根的每棵树都调整一遍,即堆构建完成

typedef int HeapType;
//构建堆,传入一个无序序列和序列长度,时间复杂度为O(n)
HeadType* CreateHeap(HeapType *H,int length){//由无序序列 H构建堆,该序列从索引0开始 int s;for(s=length/2-1;s>=0;s--){//建立堆AdjustHeap(H,s,length);//调整函数}return H;
}//堆排序 ---O(nlogn)
void HeapSort(HeapType *H){int s;int top;//堆顶元素出堆,表尾元素覆盖堆顶(删除表尾元素,即空出表尾单元),原堆顶元素放在表尾for(s=length;s>1;s--){//进行length-1次出堆,直到堆中只剩一个元素(该元素的索引:0)top=H[0];H[0]=H[s-1];AdjustHeap(H,0,s-1);H[s-1]=top;} 
}

2. 删除

堆中的删除操作,就是删除堆顶元素,其步骤和上文的如何调整一致,其调整函数如下

void AdjustHeap(HeapType*H,int s,int len){	//s=len/2-1//保存以索引s位置元素为根,此时s位置的结点并不满足最小堆的性质,其//他所有结点(s到len-1)位置的结点满足小顶堆的性质 int rc=H[s];int i;for(i=2*s+1;i<len;i=2*i+1){//由完全二叉树的性质:孩子结点和双亲结点的索引关系(注:结点位置从索引0开始,因此i=2*s+1而不是i=2*s)if(i<len-1&&H[i]>H[i+1])i++;//索引i是s孩子中的最小元素的索引if(rc<=H[i]) break;//若索引s处的元素小于孩子中最小的一个,则调整结束H[s]=H[i];s=i;}H[s]=rc;
}

3. 添加

往堆中添加元素,就是先把新元素放在堆的末端,再对新元素结点执行向上的操作,即让其和双亲结点比较,若新元素结点小于双亲结点则它们互换位置,若互换后,再于其双亲比较、交换,直到整棵树的根结点(索引为0的元素),若中途遇到双亲小于新元素的,则执行向上的操作结束,添加完毕

void addElement(HeapType *H,HeapType e,int len){//注:这里假设数组长度大(不会越界),len是元素的个数int newIndex=len;//新元素的索引int i=(newIndex+1)/2-1;//i是新元素的双亲的索引int eElem=e;//暂存新元素for(i;i>=0;i=(i-1)/2{//向上执行到根(0号结点)if(tElem<H[i]){H[newIndex]=H[i];newIndex=i;}else{break;	}}H[newIndex]=eElem;
}

四、复杂度分析

4.1 时间复杂度

创建堆,是从非叶子结点 ⌊ n / 2 ⌋ \lfloor n/2\rfloor n/2位置的元素开始到根,要调整的内部结点总数有 ⌊ n / 2 ⌋ \lfloor n/2\rfloor n/2,这些结点分布在多个层次,而构建堆过程中,每次循环都要调用一次调整函数AdjustHeap(),其每次执行调整函,其中需要比较的次数和其结点所在的树中的层次到叶子结点的深度有关(最坏的情况下)。
推导过程如下:
假设已知现在有目标堆是一个满堆,即其对应结点总数为n=2h-1的完全二叉树(也是满二叉树),深度为h,根结点处于第1层。我们处于第h-1层的每个非叶子结点向下调整时最多比较一次,第h-2层的最多比较2次…,第一层的根结点则比较n-1次(注:这里没计入筛选孩子中最小值的那一次比较)。第一层结点数:21-1=1,第二层结点数:22-1…第h-1层的结点总数:2h-2,则总的比较次数S=可能比较抽象,如下表

树的层次结点数比较次数
第1层1h-1
第2层2h-2
第3层22h-3
h-12h-21

则总的比较次数:
S = ( h − 1 ) + 2 ∗ ( h − 2 ) + 2 2 ∗ ( h − 3 ) + . . . + 2 h − 3 ∗ 2 + 2 h − 2 ∗ 1 = 2 h − h − 1 S=(h-1)+2*(h-2)+2^2*(h-3)+...+2^{h-3}*2+2^{h-2}*1=2^h-h-1 S=(h1)+2(h2)+22(h3)+...+2h32+2h21=2hh1

又由于n = 2h - 1,即 h=log2(n+1),则代入上式中,S=n-h,即创建堆时总比较次数S为O(n)级。往往堆排序过程中,就包含建堆(O(n))和排序两个过程,后者每输出一个堆顶元素,则执行一次对根结点的调整(比较的次数规模:O(h)),即时间复杂度为:O(log2n),综合为:O(nlog2n)

4.2 空间复杂度

常数级:O(1)

五、总结

堆排序,在排序过程中使用常数个辅助单元,其建堆时间为O(n),之后执行n-1次对当前的根向下的操作,不管给定的初始序列是有序还是无序,其用堆来排序的最好、最坏、平均时间复杂度均为:O(nlog2n),同时它是一种不稳定的排序,虽然堆排序速度很快,和快速排序时间复杂度一个水平,但其速度却不如快速排序(和时间复杂度的常数因子有关)。快速排序虽然很快,但是最坏的情况下时间复杂度达到O(n2),空间复杂度达到O(n)
(注:一般说某排序算法时间复杂度是多少,通常指平均情况下的)

相关文章:

堆【数据结构C语言版】【 详解】

目录-笔记整理 一、思考二、堆概念与性质三、堆的构建、删除、添加1. 构建2. 删除3. 添加 四、复杂度分析4.1 时间复杂度4.2 空间复杂度 五、总结 一、思考 设计一种数据结构&#xff0c;来存放整数&#xff0c;要求三个接口&#xff1a; 1&#xff09;获取序列中的最值&#…...

初识React

在最新写需求的时候&#xff0c;我遇到了一个需求&#xff0c;这个需求改后端改的不算多&#xff0c;而且也比较简单&#xff0c;但是在改前端的时候&#xff0c;很复杂。因为我们这个项目用的是React做前端的&#xff0c;而我对于前端知识没有了解&#xff0c;所以理解很多代码…...

VUE 开发——AJAX学习(三)

一、async函数和await async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为&#xff0c;而无需刻意地链式调用Promise async写在函数声明的前面&#xff1b;在async函数内&#xff0c;使用await关键字&#xff0c;获取Promise对象“成功状态”结果值 &…...

C++杂项

作业&#xff1a; 将之前实现的顺序表、栈、队列都更改成模板类 顺序表 #include <iostream>using namespace std;template<typename T>class SeqList { private:T *ptr;int size; //总长度int len 0; //当前顺序表实际长度public://初始…...

Gelatinous Cube Sphere - Bonus Files 2 - Atavism

这是Gelatinous Cube & Sphere Pack的奖励文件包。 奖励文件&#xff1a; ⭐ 概念艺术 也可在Monster Bundle #2中使用。 下载&#xff1a;​​Unity资源商店链接资源下载链接...

锐捷—NAT地址映射+IPsec隧道

任务目标 在出口路由器R3上将R5私网地址1对1映射的公网地址与R1建立IPsec隧道&#xff0c;使得R4在访问R5的映射公网地址时&#xff0c;可以进行IPsec隧道的转发 要求&#xff1a; 1、R4和R5可通过NAT转换正常访问互联网地址&#xff08;R2的lo0&#xff09; 2、R5的私网地…...

index.html 调用 ajax

index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>AJAX 请求示例</title><script>// 封装 Ajax 为公共函数&#xff1a;传入回调函数 success 和 failfunction myAjax (url, suc…...

uniapp学习(003-1 vue3学习 Part.1)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战&#xff0c;开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第11p-第p14的内容 文章目录 vue3使用介绍插值表达式例子时间戳随机数输出函数的值 ref响应式数据变量v-bind 绑…...

计算机毕业设计 基于深度学习的短视频内容理解与推荐系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

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

JavaScript网页设计案例深度解析:从理论到实践

前言 在现代前端开发中&#xff0c;JavaScript 是赋予网页生命的关键技术。静态的 HTML 和 CSS 虽然能创建美观的页面&#xff0c;但当我们需要增强用户交互和页面响应时&#xff0c;JavaScript 无疑成为最得力的工具。从程序员的角度来看&#xff0c;JavaScript 设计不仅仅是…...

spark-sql建表数据同步到hive

1、基础环境 组件版本备注hadoop3.4.0官方下载hive3.1.3自编译sparkspark-3.5.3-bin-hadoop3官方下载&#xff0c;需要内置hive的jar相关内容paimon0.9.0Maven官方下载jdk1.8.0_41maven3.9.6固定版本 2、停止服务、清理日志 先停止&#xff0c;清理数据 sudo kill -9 $(ps -ef…...

Django上下文处理器

1创建 &#xff08;如frontend目录下&#xff09;category_processors文件&#xff1a; def categories(request):from backend.models import Categorycategory_list Category.objects.all()return {category_list:category_list}这里&#xff0c;必须返回一个字典。 2&…...

旭升集团携手纷享销客,构建全方位客户关系管理平台

宁波旭升集团股份有限公司&#xff08;以下简称“旭升集团”&#xff09;自2003年成立&#xff0c;总部位于中国宁波&#xff0c;集团设有压铸、锻造、挤压、集成四大事业部&#xff0c;在亚洲、欧洲、美洲等地均设立研发中心及制造基地&#xff0c;产品主要覆盖新能源汽车的电…...

uniapp 知识点

自定义导航 在page.json navigationstyle":"custom"navigateTo传参 页面传参只能onLoad(option)里面拿 px和upx的关系 在750设计图中&#xff0c;1px1upx 路由 navigateBack返回上一页 重定向 其实就是把当前页面干掉了 公共组件和页面共同点 computed,watc…...

慢病中医药膳养生食疗管理微信小程序、基于微信小程序的慢病中医药膳养生食疗管理系统设计与实现、中医药膳养生食疗管理微信小程序的开发与应用(源码+文档+定制)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…...

解决 Android WebView 无法加载 H5 页面常见问题的实用指南

目录 1. WebView 简介 2. 常见问题 3. 网络权限设置 4. 启用 JavaScript 5. DOM Storage 的重要性 6. 处理 HTTPS 问题 7. 设置 WebViewClient 8. 调试工具 9. 其他调试技巧 10. 结论 相关推荐 1. WebView 简介 Android WebView 是一种视图组件&#xff0c;使得 And…...

Ollama本地部署大模型及应用

文章目录 前言一、下载安装1.Mac2.Windows3.linux4.docker5.修改配置&#xff08;可选&#xff09;1.linux系统2.window 系统3.mac系统 二、Ollama使用1.命令2.模型下载3.自定义模型4.API 服务 三、Open WebUI 使用四、Dify使用 前言 Ollama 是一个专注于本地部署大型语言模型…...

读代码UNET

这个后面这个大小怎么算的&#xff0c;这参数怎么填&#xff0c;怎么来的&#xff1f; 这是怎么看怎么算的&#xff1f; 这些参数设置怎么设置&#xff1f;卷积多大&#xff0c;有什么讲究&#xff1f;...

【java】前端RSA加密后端解密

目录 1. 说明2. 前端示例3. 后端示例3.1 pom依赖3.2 后端结构图3.3 DecryptHttpInputMessage3.4 ApiCryptoProperties3.5 TestController3.6 ApiCryptoUtil3.7 ApiDecryptParamResolver3.8 ApiDecryptRequestBodyAdvice3.9 ApiDecryptRsa3.10 ApiCryptoProperties3.11 KeyPair3…...

机器学习 | Scikit Learn中的普通最小二乘法和岭回归

在统计建模中&#xff0c;普通最小二乘法&#xff08;OLS&#xff09;和岭回归是两种广泛使用的线性回归分析技术。OLS是一种传统的方法&#xff0c;它通过最小化预测值和实际值之间的平方误差之和来找到数据的最佳拟合线。然而&#xff0c;OLS可以遭受高方差和过拟合时&#x…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...