堆
时间:2022-07-28
本文章向大家介绍堆,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
前言
堆,顾名思义,是长得像个草堆一样的数据结构。但在计算机存储里面,堆一般使用数组来表示。
按照堆的性质区分,可分为大顶堆,小顶堆。
大顶堆:所有的parent节点值都要大于
其child节点。
小顶堆:所有的parent节点值都要小于
其child节点。
堆有三个主要的操作:
- Heaplify,时间复杂度O(lgn),作用是维护堆的性质。 对于某个节点,如果不满足堆的性质,需要堆这个节点加一调整。调整的流程是,以大顶堆为例,倘若parent节点小于其子节点,需要进行交换,交换后,被交换的子节点也可能不满足大顶堆的性质,需要堆这个子节点继续进行heaplify。以下是算法导论伪代码 1234567891011Max_Heaplify(A,i): # 对大顶堆A的位置i处进行调整,A的本质是一个数组 l = Left(i) # l表示i处节点的左孩子位置 r = Right(i) # r表示i处节点的右孩子位置 if l<=A.heap_size() and A[l]>A[i]# 若左孩子大于parent节点值 largest = l else largest = i if r<=A.heap_size() and A[r]>A[i]# 若右孩子大于parent节点值 largest = r if largest!=i #当最大值不是在i处 swap(A[i],A[largest]) Max_heaplify(A,largest)# 对被交换的节点进行Max_Heaplify
- Build_Heap,时间复杂度O(n),作用是使用n个元素建立一个堆。 对于给定的数组A,将他调整为一个堆。需要做的是从最后一个非叶子节点开始,一直到根节点,不断进行Heaplify。最后一个非叶子节点恰好位于元素中间位置。以建立一个大顶堆为例,以下是算法导论伪代码 1234BUild_Max_Heap(A):# A的本质是一个数组,调整结束后还是一个数组 A.heap_size = A.length for i= A.length/2 downto 1: Max_Heaplify(A,i)
- Heap_insert,时间复杂度O(lgn),作用是向堆中插入一个元素。首先需要在数组末尾增加一个元素,数组长度加一。并不断将该元素与其父节点进行比较,如果不满足堆的性质,则发生交换。交换后的父节点也可能不满足堆的性质,因此需要继续调整。将该父节点与他的父节点进行调整,一直到满足堆的性质,或调整到了根节点。以大顶堆为例: 1234567Max_Heap_Insert(A,elem): A.length = A.length+1 # 数组长度加一 A[length+1] = elem # 在数组末尾加入该元素 pos = A.length # 最后的位置 while pos>1 and A[parent(pos)]<A[pos]: # 调整加入节点与父节点的关系 swap(A[pos],A[parent(pos)]) pos = parent(pos)
堆引申出来的堆排序
如果要对数组进行升序排序,需要使用大顶堆。建立大顶堆后,将大顶堆的堆顶元素与堆末尾元素进行交换,然后再调整交换后的堆顶,不过此时堆的大小减一,最后位置元素不可参与堆调整范围里。如此反复。
HeapSort(A):
BUild_Max_Heap(A)
for i = A.lenght to 2: # 当堆只剩一个元素,不用调整了,所以到2
swap(A[1],A[i])# 交换堆顶元素与堆末尾元素
A.heap_size = A.heap_size-1
Max_Heaplify(A,1)
C++ STL中与heap有关操作
- make_heap() 用给定的数据建立一个堆,默认大顶堆,小顶堆要设置比较函数,保证最大值在所给范围的最前面,其他值的位置不确定
- push_heap() 往堆中压入一个元素
- pop_heap() 排出堆顶元素
- is_heap():这个函数用于检查容器是否是heap。
- is_heap_until():-此函数第一个不满足堆性质的元素迭代器。
- sort_heap() 堆排序,默认升序,对象必须已经是堆
#include<bits/stdc++.h>
using namespace std;
void printVec(vector<int> nums)
{
for (int i = 0; i < nums.size(); ++i)
cout << nums[i] << " ";
cout << endl;
}
int main()
{
locale::global(std::locale(""));
vector<int> v1 = { 20, 30, 40, 25, 15 };
cout << "原始数组v1:";
printVec(v1);
make_heap(v1.begin(), v1.end());//将vector v1弄成了大顶堆,v1还是vector,不过具有heap性质
cout << "make_heap以后:";
printVec(v1);
//make_heap(v1.begin(), v1.end(),greater<int>());//将vector v1弄成了大顶堆
//cout << "堆顶元素" << v1.front() << endl;
v1.push_back(50);
push_heap(v1.begin(), v1.end());
cout << "push 一个元素以后:";
printVec(v1);
//push_heap之前还是push_back了一下,这么看来和make_heap好像没啥区别
pop_heap(v1.begin(), v1.end());//将堆顶元素与最后一个元素交换,并未真正删除
v1.pop_back();
cout << "pop_heap以后:";
printVec(v1);
//判定vector v1是否为堆
is_heap(v1.begin(), v1.end()) ?cout << "The container is heap " :cout << "The container is not heap";
cout << endl;
//堆排序。仅对已经是堆的v1进行堆排序,不然出错,结果不对
sort_heap(v1.begin(), v1.end());
cout << "堆排序之后: ";
for (int &x : v1)
cout << x << " ";
cout << endl;
vector<int> v2 = {80,30, 45,1, 55, 15 };
cout << "原始数组v2:";
printVec(v2);
auto it = is_heap_until(v2.begin(), v2.end());
// Displaying heap range elements
cout << "从v2开始到第一个不满足堆性质的元素: ";
for (auto it1 = v2.begin(); it1 != it; it1++)
cout << *it1 << " ";
return 0;
}
- priority_queue
//升序队列
priority_queue <int,vector<int>,greater<int>> q;
for (int n : {1, 8, 5, 6, 3, 4, 0, 9, 7, 2})
q.push(n);
print_queue(q);
将数组的元素相加直到每个元素都大于等于k
描述:给定一个数组,和一个K值,将数组中的一些元素拿出后再相加后再加入到数组中,一直到数组中所有元素都大于等于K。求这最小相加次数。
input:arr = {1 10 12 9 2 3} K = 6
输出:2
解释:首先将拿出数组中的1和2相加,得到3,再将3加入到数组中,数组变成了[3,10,12,9,3],然后再拿出3 和3,并相加,得到6,再将6加入到数组中,数组变成了[6,10,12,9],现在数组中的所有元素都大于等于6。因此,需要相加两次。
其实就是霍夫曼编码。用原数组建成一个小顶堆,之后取堆顶最小的两个元素,相加后再加入到堆中,一直到这个小顶堆的堆顶大于给定的K。
int countMinOps(vector<int>&nums, int k)
{
int ret = 0;
priority_queue<int, vector<int>, greater<int>>q;
for (auto i : nums)q.push(i);//建小顶堆
while (q.top() < k&&q.size()) {
int a = q.top();
q.pop();
int b= q.top();
q.pop();
q.push(a + b);
ret++;
}
return ret;
}
- 腾讯 DCI 上线基于集中控制的 SR-TE 方案
- 如何从VS2003升级到VS2008
- js中多个Date对象变量间赋值互相影响
- 并发编程之Executor,Executors,ExecutorService和ThreadPoolExecutor
- 【DeveMobile实例】d3.js 与Trianglify 制作SVG格式Low-Poly 特效
- 未来人工智能将把人类分为3层,而你会在哪一层呢?
- IIS 7.0探索用于 Windows Vista 的 Web 服务器和更多内容
- 初学Python 之抓取当当网图书页面目录并保存到txt文件
- JavaScript 基础(二)数组
- 限制扫码付款额度,支付宝和微信要被“祭旗”?
- 拖动条SeekBar及星级评分条
- 【DeveMobile实例】利用Mobile Detect 制作单独移动端页面项目
- 互联网+智能物流高峰论坛举行运的易现场签约完成战略布局
- Quartz.net通过配置文件来完成作业调度
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php+pdo实现的购物车类完整示例
- CentOS7怎么执行PHP定时任务详解
- Linux下PHP+Apache的26个必知的安全设置
- linux中ssh免密通信的实现
- 怎么修改CentOS服务器时间为北京时间
- Laravel5.1 框架控制器基础用法实例分析
- Laravel5.1 框架模型软删除操作实例分析
- Laravel 手动开关 Eloquent 修改器的操作方法
- 怎么测试Linux下tcp最大连接数限制详解
- Laravel 5.1 框架Blade模板引擎用法实例分析
- 使用pygame实现垃圾分类小游戏功能(已获校级二等奖)
- Linux 系统下安装JDK1.8的教程详解
- php学习笔记之字符串常见操作总结
- Laravel5.1 框架模型工厂ModelFactory用法实例分析
- 关于AIX挂载NFS写入效率低效的解决办法