数据结构之堆——学习笔记

1.堆的简介:

 

接下来看一下堆的建立;

 

接下来是如何在堆中插入数据以及删除数据:

 

 

 

大根堆的插入操作类似只是改变了一下大于和小于符号,同时插入操作的时间复杂度为O(logn)。

 

 

 

 来看几个问题:

答案当然是不可以:

 

这样的话就能根据原堆的末尾数字的大小来判断是应该尝试将它往上还是下进行移动。

 来看看STL里面的优先队列:

 

 

 值得注意的是 用优先队列是没有clear操作的。

接下来看几道例题:

1.堆排序:

 

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int n,heap[N],x,len=0;
inline void up(int x){while(x>1 && heap[x]<heap[x/2]){swap(heap[x],heap[x/2]);x/=2;}
}
inline void down(int k){while(k+k<=len){int j=k+k;if(j+1<=len && heap[j+1]<heap[j]) ++j;if(heap[j]>=heap[k]) break;swap(heap[k],heap[j]);k=j;}
} 
int main(){cin>>n;for(int i=1;i<=n;i++){cin>>x;heap[++len]=x;up(len);}for(int i=1;i<=n;i++){cout<<heap[1]<<' ';swap(heap[1],heap[len]);--len;down(1);}return 0;
}

事实上用优先队列来做会非常的简单:

#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int>>q;
const int N=1e5+100;
int n;
/*inline void up(int x){while(x>1 && heap[x]<=heap[x/2]){swap(heap[x],heap[x/2]);x/=2;}
}
inline void down(int x){while(x+x<=len){int y=x+x;if(y+1<=len && heap[y+1]<heap[y])  ++y;if(heap[y]>=heap[x]) break;swap(heap[y],heap[x]);x=y;}
}*/
int main(){cin>>n;for(int i=1;i<=n;i++){int x;cin>>x;q.push(x);}	for(int i=1;i<=n;i++){cout<<q.top()<<' ';q.pop();}return 0;
}

使用小根堆的话是需要背一下优先队列的写法,有一点长。

接下来看一下第二题:

合并数列:

 这道题目的数据范围如果给的很小的话其实可以直接考虑模拟做法,但是实际上这道题目并没有那么的简单,接下来看代码,我在上面给了注释。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;//这里的N要比序列的个数上限设置的更大
int n,len,m;//n个序列,len代表当前读入的堆的序列的个数,m是最后要输出的数字个数
struct xulie{int v,delta;//v代表某一序列当前的堆顶元素,delta代表对应序列的k值
}heap[N];
//对新读入的序列试着将他往上面排的函数
inline void up(int x){while(x>1 && heap[x].v<=heap[x/2].v){swap(heap[x],heap[x/2]);x/=2;}
}
//将堆首的元素试着往下排
inline void down(int x){while(x+x<=len){int y=x+x;if(y+1<=len && heap[y+1].v<heap[y].v)  ++y;if(heap[y].v>=heap[x].v) break;swap(heap[y],heap[x]);x=y;}
}
int main(){cin>>n;for(int i=1;i<=n;i++){int k,b;cin>>k>>b;heap[++len].v=b;heap[len].delta=k;up(len);}cin>>m;for(int i=1;i<=m;i++){cout<<heap[1].v<<' ';heap[1].v+=heap[1].delta;//输出堆顶序列这时候的值之后,对该序列的v值加一个delta并将加了之后的堆顶序列试着往下排down(1);}return 0;
}

这道题的做法还是很有意思的。

接下来看一下第三个题:

大富翁游戏:

 费了九牛二虎之力,可算是搞明白了。。。

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct Info{int v,pos;
}heap1[100001],heap2[100001];
int n,m,len1,len2,s1[100001],s2[100001];
inline void up1(int k){while(k>1 && heap1[k].v<heap1[k/2].v){swap(heap1[k],heap1[k/2]);s1[heap1[k].pos]=k;s1[heap1[k/2].pos]=k/2;k/=2;}
}
inline void down1(int k){while(k+k<=len1){int j=k+k;if(j+1<=len1 && heap1[j+1].v<heap1[j].v)++j;if(heap1[k].v<=heap1[j].v) break;swap(heap1[k],heap1[j]);s1[heap1[k].pos]=k;s1[heap1[j].pos]=j;k=j;}
}
inline void up2(int k){while(k>1 && heap2[k].v>heap2[k/2].v){swap(heap2[k],heap2[k/2]);s2[heap2[k].pos]=k;s2[heap2[k/2].pos]=k/2;k/=2;}
}
inline void down2(int k){while(k+k<=len2){int j=k+k;if(j+1<=len2 && heap2[j+1].v>heap2[j].v)++j;if(heap2[k].v>=heap2[j].v) break;swap(heap2[k],heap2[j]);s2[heap2[k].pos]=k;s2[heap2[j].pos]=j;k=j;}
}
int main(){cin>>n;len1=len2=0;for(int i=1;i<=n;i++){heap1[++len1].v=100;heap1[len1].pos=i;s1[i]=len1;up1(len1);heap2[++len2].v=100;heap2[len2].pos=i;s2[i]=len2;up2(len2);}cin>>m;for(int i=1;i<=m;i++){int x;cin>>x;if(x==1){int y,z;cin>>y>>z;heap1[s1[y]].v+=z;up1(s1[y]);down1(s1[y]);heap2[s2[y]].v+=z;up2(s2[y]);down2(s2[y]);}else{cout<<heap2[1].v<<' '<<heap1[1].v<<endl;}}return 0;
}

这里代码中使用了两个堆,heap1heap2,分别用来维护最小堆和最大堆。s1s2 数组用来记录每个人在堆中的位置。代码中的堆结构的使用主要是为了在O(log n)的时间复杂度内找到当前最高和最低资金,以提高效率。在每次资金变动后,通过调整堆,保证堆顶元素分别是当前最小和最大资金。

最后一个题:动态中位数

这里是代码:

#include<bits/stdc++.h>
using namespace std;
int n;
priority_queue<int>a,b;
int main(){cin>>n;int x;cin>>x;a.push(x);cout<<a.top()<<' ';for(int i=1;i<=n/2;i++){int x,y,z=a.top();cin>>x>>y;if(x<z)a.push(x);else b.push(-x);if(y<z)a.push(y);else b.push(-y);if(a.size()-b.size()==3){b.push(-a.top());a.pop();} else if(b.size()-a.size()==1){a.push(-b.top());b.pop();}cout<<a.top()<<' ';}return 0;
}

 

  1. priority_queue 的使用:定义了两个优先队列(堆),ab。它们用于存储输入数字,其中 a 是最大堆,b 是最小堆。

  2. 第一个数字的处理:从输入中读取第一个数字 x,将其压入最大堆 a 中,然后输出当前中位数(即最大堆的堆顶元素)。

  3. 循环处理每个数字对(x,y):

    • 如果 x 小于当前中位数(即最大堆的堆顶元素 a.top()),则将 x 压入最大堆 a
    • 否则,将 -xx 的相反数)压入最小堆 b
    • 如果 y 小于当前中位数,则将 y 压入最大堆 a
    • 否则,将 -yy 的相反数)压入最小堆 b
  4. 调整堆大小:在每次插入后,检查两个堆的大小关系:

    • 如果最大堆 a 的大小比最小堆 b 大 3,将最大堆的堆顶元素弹出并压入最小堆 b
    • 如果最小堆 b 的大小比最大堆 a 大 1,将最小堆的堆顶元素弹出并取其相反数压入最大堆 a
  5. 输出中位数:每次插入后,输出当前中位数(即最大堆的堆顶元素 a.top())。

  6. 这段代码通过维护最大堆和最小堆,根据输入的数字实时调整堆,以便高效地计算中位数。在中位数的计算过程中,通过在两个堆之间调整元素,确保了两个堆的大小差距在一个合理的范围内。这样做的目的是为了避免在求中位数时需要对所有数据进行排序的开销,从而实现更加高效的中位数计算

希望这一篇学习笔记对读者有所帮助,让我们共同进步。

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

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

相关文章

从零开始C++精讲:第一篇——C++入门

文章目录 前言一、C关键字二、命名空间2.1引子2.2命名空间定义2.3命名空间的使用 三、C输入和输出3.1输出3.2输入 四、缺省参数4.1全缺省4.2半缺省 五、函数重载5.1重载概念 六、引用6.1定义6.2引用的使用示例6.2.1引用作参数6.2.1引用作返回值 6.3传值、传引用效率比较6.4常引…

【亚马逊云科技】使用Helm 3为Amazon EKS部署Prometheus+Grafana监控平台

文章目录 1. 创建Kubernetes命名空间2. 添加Prometheus社区helm chart3. 安装prometheus4. 检查Prometheus Pod运行状况5. 检查Prometheus Service部署情况6. 修改服务访问端口类型7. 访问Prometheus数据收集情况8. 访问Grafana9. 设置数据源10. 查看Kubernetes各类性能可视化参…

深度学习|4.1 深L层神经网络 4.2 深层网络的正向传播

4.1 深L层神经网络 对于某些问题来说&#xff0c;深层神经网络相对于浅层神经网络解决该问题的效果会较好。所以问题就变成了神经网络层数的设置。 其中 n [ i ] n^{[i]} n[i]表示第i层神经节点的个数&#xff0c; w [ l ] w^{[l]} w[l]代表计算第l层所采用的权重系数&#xff…

详细平稳解

1.详细平衡 定义&#xff1a;一个在高斯白噪声激励下的动力学系统在状态空间中如果用如下运动方程描述&#xff1a; d d t X j \frac{d}{dt}\mathbf{X}_{j} dtd​Xj​ f j ( X ) f_{j}(\mathbf{X}) fj​(X) ∑ l 1 m g j l ( X ) W l ( t ) \sum_{l1}^{m}g_{jl}(\mathbf{X})W…

Multisim各版本安装指南

Multisim下载链接 https://pan.baidu.com/s/1En9uUKafhGOqo57V5rY9dA?pwd0531 1.鼠标右击【Multisim 14.3(64bit)】压缩包&#xff08;win11及以上统需先点击“显示更多选项”&#xff09;选择【解压到 Multisim 14.3(64bit)】。 2.打开解压后的文件夹&#xff0c;双击打开【…

Nacos与Eureka

一、前言 在构建和管理微服务架构时&#xff0c;选择适当的服务注册中心至关重要。Nacos和Eureka都是微服务体系结构中常用的服务注册和发现工具。本文将探讨它们之间的区别&#xff0c;帮助开发者在选择适合其项目需求的注册中心时做出明智的决策。 二、架构和适用场景 Nacos …

[嵌入式C][入门篇] 快速掌握基础2 (数据类型、常量、变量)

开发环境&#xff1a; 网页版&#xff1a;跳转本地开发(Vscode)&#xff1a;跳转 文章目录 一、基本变量大小和范围&#xff08;1&#xff09;在8位/32位单⽚机中&#xff1a;测试代码结果&#xff1a;64位机器结果&#xff1a;32位机器&#xff08;单片机&#xff09;无对齐限…

超实用的测试万能法则 —— 帕累托分析!

20/80原则来源于意大利经济学家维弗雷多•帕累托&#xff08;Villefredo Pareto&#xff09;提出的财富占比帕累托原则&#xff1a;80%的财富是掌握在20%的人手中的&#xff0c;而余下的80%的人只占那剩余的20%财富&#xff0c;而后这个理论延伸为&#xff1a;至关重要的少数和…

程序员副业之无人直播助眠

介绍和概览 大家好&#xff0c;我是小黑&#xff0c;本文给大家介绍一个比较轻松简单的副业&#xff0c;无人直播助眠副业。 这个项目的核心就是通过直播一些助眠素材来赚钱。比如你可以放一些舒缓的雨声之类的&#xff0c;吸引观众进来。然后&#xff0c;咱们可以挂个小程序…

案例分析——如何优化跨境直播网络

跨境直播 风口已至 这些年越来越多商家加入直播带货行列&#xff0c;各种玩法日渐成熟。而TikTok作为当前国外最火爆的直播平台&#xff0c;不少卖家都会定期做TikTok直播引流&#xff0c;但时常会面临着远程访问导致直播画面模糊、卡顿掉线、延迟高&#xff0c;甚至可能限流黑…

YOLOv5改进 | Neck篇 | 利用Damo-YOLO的RepGFPN改进特征融合层

一、本文介绍 本文给大家带来的改进机制是Damo-YOLO的RepGFPN(重参数化泛化特征金字塔网络),利用其优化YOLOv5的Neck部分,可以在不影响计算量的同时大幅度涨点(亲测在小目标和大目标检测的数据集上效果均表现良好涨点幅度超级高!)。RepGFPN不同于以往提出的改进模块,其…

剧本杀小程序/APP搭建,增加玩家游戏体验

近年来&#xff0c;剧本杀游戏成为了年轻人娱乐的新方式&#xff0c;受到了年轻人的追捧。 剧本杀是一种新型的社交游戏&#xff0c;在游戏中&#xff0c;玩家不仅可以进行角色扮演&#xff0c;也能够交到好友&#xff0c;符合当下年轻人的生活模式。 小程序、app是当下剧本杀…