二、数据结构10:堆 模板题+算法模板(堆排序,模拟堆)

news2024/11/18 15:50:18

文章目录

  • 算法模板
    • 堆题目代码模板
    • 堆的原理
      • down操作理解:
      • up操作理解
      • 建堆操作
      • 关于heap_swap中存的映射数组理解(模拟堆题目中用到)
  • 模板题
    • 堆排序
      • 原题链接
      • 题目
      • 思路
      • 题解
    • 模拟堆
      • 原题链接
      • 题目
      • 思路
      • 题解

算法模板

堆题目代码模板

// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
int h[N], ph[N], hp[N], size;

// 交换两个点,及其映射关系
void heap_swap(int a, int b)
{
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a], hp[b]);
    swap(h[a], h[b]);
}

void down(int u)
{
    int t = u;
    if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t)
    {
        heap_swap(u, t);
        down(t);
    }
}

void up(int u)
{
    while (u / 2 && h[u] < h[u / 2])
    {
        heap_swap(u, u / 2);
        u >>= 1;
    }
}

// O(n)建堆
for (int i = n / 2; i; i -- ) down(i);

堆的原理

以小根堆为例,小根堆中每个点小于等于左右儿子是递归定义的
在这里插入图片描述
在这里插入图片描述

down操作理解:

在这里插入图片描述
down完后:
在这里插入图片描述
代码实现:
在这里插入图片描述

up操作理解

在这里插入图片描述
up完后:
在这里插入图片描述

各种操作的实现思路:
在这里插入图片描述
在这里插入图片描述

建堆操作

在这里插入图片描述
建堆:一个一个插时间复杂度为O(nlogn)
使用上图中该方法从n/2 down到1,时间复杂度为O(n)

关于heap_swap中存的映射数组理解(模拟堆题目中用到)

由于该题目中需要对“第k个插入”的数进行处理,因此需要存两个数组来知道“第k个插入”的数在堆数组中的下标位置,在交换操作时也需要交换对应的映射。

ph[j]:第j个插入的点在堆数组中下标为k
hp[k]:堆里面下标为j的点对应的ph数组中的下标为j

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

模板题

堆排序

原题链接

https://www.acwing.com/problem/content/840/

题目

输入一个长度为 n
的整数数列,从小到大输出前 m
小的数。

输入格式
第一行包含整数 n
和 m

第二行包含 n
个整数,表示整数数列。

输出格式
共一行,包含 m
个整数,表示整数数列中前 m
小的数。

数据范围
1≤m≤n≤105

1≤数列中元素≤109
输入样例:

5 3
4 5 1 3 2

输出样例:

1 2 3

思路

建堆+down操作维护堆+删除堆顶元素操作,每次输出堆顶(h[1])即为当前最小值

题解

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10, M = 1e5 + 10;
int h[N];
int n,m;
int sizeOfH;

void down(int u){
	int t = u;
	if(u*2 <= sizeOfH && h[u*2]<h[t]) t = u*2;
	if(u*2+1 <= sizeOfH && h[u*2+1] < h[t]) t = u*2+1;
	
	if(u!=t){
		swap(h[t],h[u]);
		down(t);
	}
	
	 
} 
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>h[i];
	sizeOfH = n;
	
//	建堆 
	for(int i=n/2; i ; i--) down(i);
	
	
	while(m--){
		printf("%d ",h[1]);
		
		h[1] = h[sizeOfH];
		sizeOfH--;
		down(1);
	}
	
} 

模拟堆

原题链接

https://www.acwing.com/problem/content/841/

题目

维护一个集合,初始时集合为空,支持如下几种操作:

I x,插入一个数 x

PM,输出当前集合中的最小值;
DM,删除当前集合中的最小值(数据保证此时的最小值唯一);
D k,删除第 k
个插入的数;
C k x,修改第 k
个插入的数,将其变为 x

现在要进行 N
次操作,对于所有第 2
个操作,输出当前集合的最小值。

输入格式
第一行包含整数 N

接下来 N
行,每行包含一个操作指令,操作指令为 I x,PM,DM,D k 或 C k x 中的一种。

输出格式
对于每个输出指令 PM,输出一个结果,表示当前集合中的最小值。

每个结果占一行。

数据范围
1≤N≤105

−109≤x≤109

数据保证合法。

输入样例:

8
I -10
PM
I -10
D 1
C 2 8
I 6
PM
DM

输出样例:

-10
6

思路

在这里插入图片描述
实现堆的基本操作,但要注意的是题目中需要对“第k个插入”的数进行处理,因此需要维护ph和hp两个映射数组,并使用自定义的heap_swap方法。

题解

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;

const int N = 1e5 +10;

int h[N],ph[N],hp[N],sizeOfH;
int n;

void heap_swap(int a,int b){//因为操作中需要对“第k个插入”的数进行删除和修改操作,因此需要使用映射版的swap 
	swap(ph[hp[a]],ph[hp[b]]);//ph[j]:第j个插入的点在堆数组中下标为k,hp[k]:堆里面下标为j的点对应的ph数组中的下标为j 
	swap(hp[a],hp[b]);
	swap(h[a],h[b]);
}

void down(int u){
	int t = u;
	if(u*2 <= sizeOfH && h[u*2]<h[t]) t = u*2;
	if(u*2+1 <= sizeOfH && h[u*2+1]<h[t]) t = u*2+1;
	if(t != u){
		heap_swap(t,u);
		down(t);
	}
}

void up(int u){
	while(u/2 && h[u/2] > h[u]){ // 如果其父节点比该节点大,则将该节点up 
		heap_swap(u/2,u);
		u/=2;
	}
}

int main(){
	int m=0; // 全局中递增的唯一id 记录是第几个插入的数 
	cin>>n;
	while(n--){
		char op[10];
		int k,x;
		
		scanf("%s",op); // cin>>op;
		if(!strcmp(op,"I")){ //strcmp(const char *str1, const char *str2) 如果返回值小于 0,则表示 str1 小于 str2。如果返回值大于 0,则表示 str1 大于 str2。如果返回值等于 0,则表示 str1 等于 str2。
			cin>>x;
			sizeOfH++;
			m++;
			h[sizeOfH] = x;
			ph[m] = sizeOfH;
			hp[sizeOfH] = m;
			up(sizeOfH);
		} 
		else if(!strcmp(op,"PM")) printf("%d\n",h[1]);
		else if(!strcmp(op,"DM")) {
			heap_swap(1,sizeOfH);
			sizeOfH--;
			down(1);
		}
		else if(!strcmp(op,"D")){
			cin>>k;
			k = ph[k];  // 找到第k个插入的数在堆数组中的坐标
			heap_swap(k,sizeOfH);
			sizeOfH--;
			down(k); // down和up其实只有其中一个起作用,但方便起见这样写 
			up(k);
		}
		else{
			cin>>k>>x;
			k = ph[k]; // 找到第k个插入的数在堆数组中的坐标
			h[k] = x;
			down(k);
			up(k);
		}
	}
	return 0; 
}

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

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

相关文章

【啥都生】分类项目中的模型搭建代码解析

def build_model(cfg):if isinstance(cfg, list):modules [eval(cfg_.pop("type"))(**cfg_) for cfg_ in cfg]return Sequential(*modules)else:return eval(cfg.pop("type"))(**cfg)b站up啥都生维护的分类项目 这段代码的功能是完成模型搭建&#xff0c;…

Cesium态势标绘专题-文本标注(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

Vue模版语法

先看以下例题是回顾vue的用法 <body><div id"box">{{myname}} - {{myage}}</div><script>var vm new Vue({el:"#box",data:{myname:"lyx",myage:26}})</script></body> 运行结果如下&#xff1a;vue对象被…

什么是熵?

熵&#xff08;Entropy&#xff09;是一个重要的概念&#xff0c;最初出现在热力学领域&#xff0c;用于描述系统的混乱程度或不确定性。熵也被广泛应用于信息理论、统计学和计算机科学等领域。通常来讲&#xff0c;熵&#xff0c;是对混乱程度、不确定程度的度量。熵越大&…

【测试学习三】软件测试的生命周期 BUG的相关知识

目录 一、软件测试的生命周期&#xff08;重要&#xff09; &#x1f351;1、软件的生命周期&#xff1f; &#x1f351;2、软件测试的生命周期&#xff1f; 二、关于BUG &#x1f351;1、如何描述与定义一个BUG&#xff1f;&#xff08;了解&#xff09; &#x1f351;2…

分时电价调整后上海储能项目投资回收期分析-安科瑞黄安南

2022年12月16日&#xff0c;上海市发改委发布《关于进一步完善我市分时电价机制有关事项的通知》(沪发改价管〔2022〕50号)。通知明确上海分时电价机制&#xff0c;一般工商业及其他两部制、大工业两部制用电夏季&#xff08;7、8、9月&#xff09;和冬季&#xff08;1、12月&a…

Tomcat安装与管理

文章目录 Tomcat安装及管理Tomcat gz包安装&#xff1a;JDK安装&#xff1a;Tomcat安装&#xff1a;修改配置文件&#xff08;如下&#xff09;&#xff1a;服务启动配置&#xff1a; Tomcat-管理(部署jpress)&#xff1a;修改允许访问的主机修改允许管理APP的主机进入管理&…

实用干货!一文读懂Salesforce中6种数据关系类型!

Salesforce中对象之间的数据关系可能是一个棘手的话题。对于创建自定义对象的业务场景&#xff0c;需要决定使用哪些关系类型来扩展Salesforce数据模型。 01 查找关系 查找关系&#xff08;Lookup Relationships&#xff09;是一种松散耦合&#xff08;loosely coupled&…

【SQL】-【计算两个varchar类型的timestamp的毫秒差】

背景 TRANSTAMP3、TRANSTAMP2在Oracle数据库中的类型为varchar&#xff0c;但实际保存的值是时间戳timestamp类型&#xff0c;现在要计算二者的毫秒差 Oracle或MySQL extract(second from (to_timestamp(TRANSTAMP3,yyyy-mm-dd hh24:mi:ss.ff) - to_timestamp(TRANSTAMP2,yyy…

盘点那些不想骑车的原因和借口。

在自行车骑行的热潮中&#xff0c;我们都会找到各种千奇百怪的借口来解释我们为什么不想骑。本文将结合当前热点话题和趋势&#xff0c;从心理学、文化等多个角度&#xff0c;深入探讨这些借口背后的原因。 首先&#xff0c;我们不能忽视的是&#xff0c;骑行是一项需要耐力和毅…

web集群学习

目录 简述静态网页和动态网页的区别 Webl.0 和 Web2.0 的区别 安装tomcat8&#xff0c;配置服务启动脚本&#xff0c;部署jpress应用 1、安装jdk文件&#xff1a; 2、下载tomcat的二进制包&#xff1a; 3、创建用户组和用户 创建Tomcat的登录服务脚本 此处创建的登录服务…

代码随想录算法训练营第三十二天 | 全是没接触过的知识点,要复习

以下题目多次复习 200 岛屿数量未看解答自己编写的青春版重点本题的解题思路&#xff0c;也是之前没有接触过的&#xff0c;四字总结&#xff1a;学会感染&#xff01; 题解的代码日后复习重新编写 32 最长有效括号未看解答自己编写的青春版重点这道题&#xff0c;动态规划的思…

19-2.vuex

目录 1 安装 2 挂载 2.1 vue2写法 2.2 vue3写法 3 state 3.1 声明数据 3.2 使用数据 3.3 处理数据 4 mutations 4.1 基本使用 4.2 传递参数 4.3 mutations中不能写异步的代码 5 actions 5.1 基本使用 5.2 传递参数 6 getters Vuex是做全局数据…

CAS原理解析

CAS是一种乐观锁机制&#xff0c;一种比较并交换的过程和理念&#xff0c;用来解决线程安全问题&#xff0c;具体来讲就是对共享变量值的安全更新机制。能够保证原子、可见、一致性。这种交换过程是在Unsafe类中实现。 从一段简单的代码开始来对源码做分析 public static void…

坚鹏:常德市银行业协会BLM银行数字化转型战略培训圆满结束

常德市银行业协会BLM银行数字化转型战略培训圆满结束 在数字化转型背景下&#xff0c;常德市银行业协会为了落实监管政策《关于银行业保险业数字化转型的指导意见》&#xff0c;充分认识到学习银行银行数字化转型战略的价值和重要性&#xff0c;特别举办《2023年数字化转型战略…

06 Ubuntu22.04上的miniconda3安装、深度学习常用环境配置

下载脚本 我依然是在清华镜像当中寻找的脚本。这里找脚本真的十分方便&#xff0c;我十分推荐。 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh 下载十分快速&#xff0c;10秒解决问题 运行miniconda3安装脚本 赋予执…

邀请媒体现场报道,有哪些作用?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 邀请媒体现场报道活动具有多种重要作用和意义&#xff0c;可以为你的活动带来广泛的曝光和正面影响。以下是一些邀请媒体现场报道的作用和意义&#xff1a; 1. 增加活动曝光度&#xff…

Android 自定义按钮(可滑动、点击)

按钮图片素材 https://download.csdn.net/download/Lan_Se_Tian_Ma/88151085 px 和 dp 转换工具类&#xff08;Java&#xff09; // px 和 dp 转换工具类 public class DensityUtil {/*** 根据手机的分辨率从 dip 的单位 转成为 px(像素)*/public static int dip2px(Conte…

C 语言多线程(上)

一&#xff0c;线程创建 1.1 每一个线程都有一个唯一的线程ID&#xff0c;ID类型为pthread_t&#xff0c;这个ID是一个无符号长整形数&#xff0c;如果想要得到当前线程的线程ID&#xff0c;可以调用如下函数&#xff1a; pthread_t pthread_self(void); // 返回当前线程的线…

如何设计一个自动化测试框架?

一个成熟的测试框架主要由 4 部分组成&#xff1a;基础模块、管理模块、运行模块和统计模块 基础模块 底层核心库 一般指用于操作被测试应用程序的第三方库&#xff0c;例如在 Web 端的 Selenium/WebDriver。如API端的Requests 对象库 PO模式中的页面对象 可重用组件 如一些…