数据结构-堆详解

图片:

二叉堆的父节点为这个子树的最值。

如何维护它。
我们发现它是一棵二叉树,那就自然满足若父节点为 x x x 则左儿子节点为 x × 2 x\times2 x×2 右儿子为 x × 2 + 1 x\times 2 + 1 x×2+1 这是显然的,但如果写成指针或结构体就太麻烦了,所以考虑用数组来维护它。

用一个数组 T T T 来存储这颗二叉树,根节点为 T 1 T_1 T1 根据二叉树的性质对于每个子节点 x x x 则有:

  1. x > 1 x>1 x>1 则fa[x]=i/2;
  2. 2 × x > n 2\times x>n 2×x>n x x x 没有儿子,如果 2 × x + 1 > n 2\times x+1>n 2×x+1>n x x x 没有右儿子。
  3. 如果节点 x x x 有孩子,则 x x x 的左儿子为 x × 2 x\times 2 x×2 右儿子为 x × 2 + 1 x\times 2 + 1 x×2+1

复杂度分析:

这样做由于二叉树只有 log ⁡ 2 n \log_2n log2n 层,自然单次复杂度为 O ( log ⁡ 2 n ) O(\log_2n) O(log2n)可以解决 n ≤ 1 0 6 n\leq 10^6 n106 及以下的问题。

那么该如何让这个二叉树平衡?通常使用上浮法与下沉法。
例子:
假设你已经有一个堆了,就是上面那个

这个时候你如果想要给它加入一个节点怎么办,比如说0?

先插到堆底(严格意义上来说其实0是在5的左儿子的,图没画好放不下去,不过也不影响)

然后你会发现它比它的父亲小啊,那怎么办?不符合小根堆的性质了啊,那就交换一下他们的位置

交换之后还是发现不符合小根堆的性质,那么再换

还是不行,再换

好了,这下就符合小根堆的性质了。

事实上堆的插入就是把新的元素放到堆底,然后检查它是否符合堆的性质,如果符合就丢在那里了,如果不符合,那就和它的父亲交换一下,一直交换交换交换,直到符合堆的性质,那么就插入完成了。
删除同理这里不在复述了。

代码:

插入:

void push(int x){h[++len] =x;int i=len;while(i>1 && h[i]<h[len/2]){swap(h[i],h[i/2]);i/=2;}
}

删除:

void pop(){h[1] = h[len--];int i=1;while((i<<1)<=len){int son=(i<<1);if(son<len&&h[son+1]<h[son]){son++;}if(h[son]<h[i]){swap(h[son],h[i]);i=son;}else break;}
}

STL堆:

算法竞赛中虽然STL没有手写快但是否好像实用代码:

定义一个大根堆即堆内为递减的序列

priority_queue<int> Q;

小根堆:

priority_queue<int,vector<int>,greater<int>> Q2;

使用:

插入一个数:

void insert(int x){q.push(x);
}

删除堆头:

void erase(){q.pop();
}

访问堆头

int front(){return q.top();
}

建议使用STL的堆

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

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

相关文章

Redis的特性与安装

回顾 Redis是一个在内存中存储数据的中间件&#xff0c;可以用来当数据库用&#xff0c;也可以作为缓存用(这里的缓存往往是对数据库缓存)。 中间件&#xff1a;和业务无关的服务&#xff0c;功能更加通用&#xff0c;如&#xff1a;数据库&#xff0c;缓存&#xff0c;消息队…

【笔试强训】Day1 --- 数字统计 + 两个数组的交集 + 点击消除

文章目录 1. 数字统计2. 两个数组的交集3. 点击消除 1. 数字统计 【链接】&#xff1a;数字统计 解题思路&#xff1a;模拟&#xff0c;利用数学知识&#xff0c;计算每个数字中2出现的个数。&#xff08;这里也可以将数字转换成字符串来统计字符’2’出现的个数&#xff09…

如何使用Flask搭建web程序框架并实现无公网IP远程访问本地程序

文章目录 前言1. 安装部署Flask并制作SayHello问答界面2. 安装Cpolar内网穿透3. 配置Flask的问答界面公网访问地址4. 公网远程访问Flask的问答界面 前言 Flask是一个Python编写的Web微框架&#xff0c;让我们可以使用Python语言快速实现一个网站或Web服务&#xff0c;本期教程…

bonding原理分析和问题排查

bonding原理 发送端&#xff1a; 使用网卡bond3模式&#xff08;广播模式BOND_MODE_BROADCAST&#xff09;将报文从两个网卡同时发出&#xff0c;无需修改报文。 接收端&#xff1a; 根据发送节点时间的链路通断状态&#xff0c;接收端设置一条线路为活动线&#xff0c;另一条…

免费泛域名SSL如何申请,和通配符有什么区别

-----让我们明确什么是泛域名。所谓泛域名&#xff0c;是指使用星号&#xff08;*&#xff09;作为子域名的占位符&#xff0c;它可以匹配任意子域名。-----而通配符在域名中&#xff0c;它可以出现在主域名的任何位置&#xff0c;它可以用于主域名和子域名的保护。 主要应用场…

XZ-Utils后门事件过程及启示

Part.01 背景 XZ-Utils&#xff08;曾经叫做LZMA Utils&#xff09;是一款开源的无损压缩命令行工具&#xff0c;是用C语言编写的跨平台工具&#xff0c;可以用于类Unix系统和Windows系统。在多数情况下&#xff0c;xz的压缩率要好过gzip和bzip2&#xff0c;解压速度也快过bz…

Java的数组定义和使用

目录 1.前言 2.数组的概念 3.在Java中的创建和初始化 3.1数组的创建 3.2数组的初始化 4.关于使用 4.1数组元素的访问 4.2数组的遍历 4.3length和length()的区别 5.数组其实是引用类型数据 5.1初始JVM的内存分布 5.2基本类型变量与引用类型变量的区别 5.3关于null的认识 5.4设计…

工作流JBPM画图与配置

文章目录 ☃️7.1 画图☃️7.2 配置7.2.1 配置任务办理人7.2.1.1 写死的方式配置任务办理人&#xff08;不推荐&#xff09;7.2.1.2 #{}方式配置任务办理人7.2.1.3 实现接口方式配置任务办理人7.2.1.4 方法指定方式分配任务办理人 7.2.2 配置节点属性7.2.2.1 判断节点(decision…

Sourcetree安装使用(补个笔记)

Sourcetree介绍 Sourcetree是一款免费的Git图形化客户端&#xff0c;它由Atlassian开发&#xff0c;提供了跨平台的支持&#xff0c;可运行在Windows和Mac操作系统上。Sourcetree可以让开发者更方便地使用Git来管理代码&#xff0c;不需要在命令行中输入复杂的Git命令&#xf…

HTML学习笔记:链接target属性

关于target的使用&#xff1a; <a href"https://www.baidu.com" target"_parent">网址链接</a>其中关于target四个特殊目标的理解&#xff0c;W3school上的解释为&#xff1a; HTML 标签的 target 属性 其中_black和_self两个属性很好理解&…