数据结构与算法—堆(heap)
目录
堆
1、插入
2、删除
建堆
1、堆化
2、排序
与快速排序比较
堆的应用
一、优先级队列
1、合并有序小文件:
2、高性能定时器
二、求Top K和中位数
1、TopK问题
2、利用堆求中位数(动态数据)
堆
1、堆是一个完全二叉树。(除最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列)
2、堆中一个节点的值都必须大于等于(或者小于等于)其子树中每个节点的值。对应的是大顶堆和小顶堆。
堆排序是一种原地的,时间复杂度为O(nlogn)的排序算法
大顶堆:每个节点的值都大于等于子树中每个节点值
小顶堆:每个节点的值都小于等于子树中每个节点值
堆的操作 插入与删除
1、插入
顺着节点所在的路径,向上或者向下对比(先跟最后一个数据比,依次向上),然后交换。让新插入的节点与父节点对比大小,如果满足子节点小于等于父节点,相互交换,一直重复。
2、删除
大顶堆,堆顶元素是最大元素。当我们删除堆顶元素之后,就需要把第二大的元素放到堆顶,依次迭代。直到叶子节点被删除。
问题:数组空洞,不满足完全二叉树定义。
改进 :把最后一个节点放到堆顶,然后用同样的方法比较。这就是从上往下的堆化方法。
建堆
1、堆化
从最后一个非叶子节点i = heap->elements / 2开始,使得数据满足堆的两个特性。建堆时间复杂度O(n)
void heapify(struct heap *heap, int parent)
{struct element **elem = heap->elem;int elements = heap->elements;int left, right, max;while (true) {left = parent * 2;right = left + 1;max = parent;if (left <= elements && elem[max]->data < elem[left]->data)max = left;if (right <= elements && elem[max]->data < elem[right]->data)max = right;if (max == parent)break;swap(heap, max, parent);parent = max;}
}void build_heap(struct heap *heap)
{int i;for (i = heap->elements / 2; i >= 1; i--)heapify(heap, i);
}
2、排序
按照大顶堆:数组中的第一个元素就是堆顶,我们把它跟后一个元素交换,那么最大元素就放到了下标为n的位置。再次堆化,取堆顶元素,放在n-1位置上。这样交换完数据就排序好了
void swap(struct heap *heap, int i, int j)
{struct element *tmp;tmp = heap->elem[j];heap->elem[j] = heap->elem[i];heap->elem[i] = tmp;
}int heap_sort(struct heap *heap)
{int elements = heap->elements;while (heap->elements) {swap(heap, 1, heap->elements);heap->elements--;heapify(heap, 1);}return elements;
}
排序时间复杂度 O(logn)
堆排序是不稳定的排序算法,在排序过程中,存在将堆的最后一个节点跟堆顶互换。有可能改变相同数据的原始相对顺序。
与快速排序比较
在实际开发中,为什么快速排序要比堆排序性能好
1、堆排序的数据访问方式没有快速排序友好
2、对于相同的数据,堆排序数据交换次数多余快速排序
堆的应用
一、优先级队列
队列最大特点先进先出,而优先级队列,数据的出队顺序不是先进先出,而是按照优先级来,优先级高的先出队。
堆和优先级队列非常相似,一个堆看作一个优先级队列。
1、合并有序小文件:
100个小文件,每个文件大小是100MB,每个文件中存储的都是有序的字符串。
使用优先级队列,从各文件拿出第一个string,将小文件中取出来的字符串放入到小顶堆中,100个文件的string组成的小顶堆,堆顶的元素,就是优先级队列首元素,就是最小的字符串。
将这个小字符串从堆中删除,再从小文件中取出下一个字符串,放入堆中。循环执行
时间复杂度:O(logn)
2、高性能定时器
定时器中维护很多定时任务,每个任务都设定了一个要触发执行的时间点。定时器定时扫描任务,查看任务设置的执行时间,如果到了,就拿出来执行。
每过1秒扫描一遍任务列表做法低效
1、任务定时可能很久,1s扫描很多都是徒劳
2、每次都扫描整个任务列表,如果任务表很大,必然会很耗时。
使用优先级队列
按照任务设定的执行时间,将这些任务存储在优先级队列中,队列首部存储的是最先执行的任务。
拿队首任务的执行时间点,与当前时间相减,得到时间间隔T;T就是需要等待多久。
时间到,从队首取出任务,然后再计算新的任务执行时间与当前时间点的差值。
二、求Top K和中位数
1、TopK问题
1、静态数据,数据事先确定,不会改变
维护一个大小为K的小顶堆,顺序遍历数组,从数组中取出数据与堆顶元素比较。如果比堆顶元素大,把堆顶元素删除,并且将这个元素插入到堆中;
如果比堆顶元素小,则不做处理。等数据都遍历完后,堆数据就是前K大数据。
时间复杂度:遍历数组O(n)时间复杂度,一次堆化操作需要O(logk)的时间复杂度,最坏情况下,n个元素都入堆一次,时间复杂度O(nlogk)
2、动态数据
两个操作:1、添加数据;2、询问当前的K大数据
一直维护一个K大小的小顶堆。
当有数据添加到集合中,拿堆它与堆顶元素对比。如果比堆顶元素大,就把堆顶元素删除,并将这个元素加入到堆中;如果比堆顶元素小,不变。
无论任何时候都需要查询当前的K大数据,都可以得到。
时间复杂度:如果每次询问前K大数据,基于当前的数据重新计算的话,时间复杂度O(nlogk),n表示当前数据的大小。
2、利用堆求中位数(动态数据)
先将数据排序,再将数据一分为二,维护两个堆,一个大顶堆,一个小顶堆。
当有数据插入时,如果数据小于等于大顶堆的元素,就将这个数据添加到大顶堆中;否则,小顶堆。
调整:数据插入,破坏了数据均分的特性;将一个堆顶元素,移动到另一个堆中。
插入数据涉及堆化,时间复杂度为O(logn),查找时间复杂度O(1)
数据结构与算法—堆(heap)相关推荐
- 数据结构与算法---堆的基本操作
堆的定义 堆可以看做是一种特殊的树,堆结构满足两个条件: 1.堆是一个完全二叉树. 2.堆的每一个节点的值都大于等于(或小于等于)其子节点的值. 大于等于子节点的值我们叫它:大顶堆 小于等于子节点的值 ...
- 数据结构与算法 | 堆
二叉树的顺序结构 堆的概念及结构 堆的实现 二叉树的顺序结构 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费.而完全二叉树更适合使用顺序结构存储.现实中我们通常把堆(一种二叉树)使用 ...
- 数据结构与算法——堆的原理和实现
目录 一.堆的原理 二.堆的实现 1.堆的定义 2.堆的初始化 3.向上调整算法 4.向上调整算法代码实现 5.堆的插入 6.向下调整算法 6.堆的删除 7.堆的大小 8.判断堆是否为空 总结 一.堆 ...
- 数据结构与算法(6) -- heap
binary heap就是一种complete binary tree(完全二叉树).也就是说,整棵binary tree除了最底层的叶节点之外,都是满的.而最底层的叶节点由左至右又不得有空隙. 以上 ...
- 数据结构与算法 / 堆结构
一.基本信息 1.本质 一颗特殊的树. 2.特性 完全二叉树. 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值. 3.分类 对于每一个节点的值都大于等于子节点的值的情况,该堆被称为 ...
- 算法与数据结构基础 - 堆(Heap)和优先级队列(Priority Queue)
堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值: 图片来源:这里 堆可以用数组存储,插入.删除会触发节点shift_down.shif ...
- codeforces 贪心+优先队列_算法与数据结构基础 - 堆(Heap)和优先级队列(Priority Queue)...
堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值:
- 数据结构与算法(4)——优先队列和堆
前言:题图无关,接下来开始简单学习学习优先队列和堆的相关数据结构的知识: 前序文章: 数据结构与算法(1)--数组与链表(https://www.jianshu.com/p/7b93b3570875) ...
- 数据结构之堆Heap
1. 概述 堆(也叫优先队列),是一棵完全二叉树,它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等. 2. 堆 ...
最新文章
- 用C语言实现控制台模拟显示时
- Java开发怎么达到年薪 50w ?我有一些想法和建议
- WCF异常:HTTP 无法注册,另一应用程序正在使用 TCP 端口 80
- Anaconda-- conda 创建、激活、退出、删除虚拟环境
- Oracle到出dmp
- docker中lnmp访问php页面,Docker下部署LNMP工作环境的教程(详细步骤)
- linux日志分析与痕迹清理
- Blend4开发:会飞的小鸟
- linux软件包管理 pdf,vSphere Storage Appliance 安装和管理 PDF
- 在SharePoint网站中访问Webservice被拒绝的解决方法
- HTTP / HTTPS抓包工具-Fiddler
- 微信小程序实例源码大全
- 软件设计师历年真题(链接在文末)
- 通过有限差分和matlab矩阵运算直接求解一维薛定谔方程,通过有限差分和MATLAB矩阵运算直接求解一维薛定谔方程...
- 怎样开启Win7快速启动栏以及怎样显示右下角运行程序通知
- Visual Studio使用技巧 +谷歌浏览器使用技巧总结
- 字体大小fontsize中的pt、px、em
- windows安全事件ID编号解释大全
- Airbnb(爱彼迎)产品分析报告
- python 路径格式化_吐血整理!140种Python标准库、第三方库和外部工具都有了!...
热门文章
- mtk6595资料帖和问题帖集合
- Hi-End音箱真伪(3)-巴汉著文
- 网络协议栈TSO/UFO/GSO/LRO/GRO/RSS特性
- python爬取王者_用Python爬取王者农药英雄皮肤
- jmeter 压测java代码
- 无能狂怒之@RequestParam、@PathParam、@PathVariable三者有什么区别我都不知道!
- 加快数字创新赋能实体经济 CDEC2021中国数字智能生态大会成都站今日举行
- 一位老先生对年轻人不得不说的十大忠告〔转〕
- linux克隆tf卡中的内容,TF/SD内存卡数据克隆怎样做图文详细教程
- JSON简介:什么是JSON?