最小堆

关于PriorityQueue 二叉堆的问题

こ雲淡風輕ζ 提交于 2019-12-14 21:50:09
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 场景:最近在研究java中的队列,当研究到优先队列的时候去读 PriorityQueue的源码的时候发现一种数据结构,我数据结构这块基本上上是空白,所以让我晦涩难懂啊,于是我查阅了大量资料以及手动书写程序代码测试后,终于搞懂了这种数据结构交二叉堆,其实堆就是一个数组,只不过用数组的结构来存储一颗近似二叉树 呵呵,闲话少叙,看我上代码 有关资料: 堆(数据结构) 二叉堆 堆排序 看我演示代码: package test.queue; import java.util.PriorityQueue; import java.util.Queue; /** * Author: skyline{http://my.oschina.net/skyline520} * Created: 13-6-1 上午8:07 */ public class TestQueue { public void printPriorityQueue(){ Queue<Integer> priorityQueue = new PriorityQueue<Integer>(); priorityQueue.add(1); priorityQueue.add(9); priorityQueue.add(3); priorityQueue.add(8)

能实现一个既能自动扩容又能只保留前N个最值的优先级队列吗

孤街醉人 提交于 2019-12-14 19:46:28
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 注意:这里讨论的是基于堆实现的优先级队列! 基于java自带的PriorityQueue是一个能自动扩容的优先级队列,而lucene实现了一个能够维护固定尺寸的队列(只保留最大或最小的前N个数值)但是不能自动扩容。于是想象能着能不能将两者的优点结合,做一个既能自动扩容,又能维护固定尺寸的优先级队列。 实际上最后没能实现,原因如下: 假设我们的需求是从队列中获取最小的元素 1、既然是获取最小的元素,那么该堆一定是个最小堆(即堆顶部的元素值最小); 2、如果要保留最小的前N个数值,每次在插入新的元素时需要将队列中最大的元素给替换掉,这样我们就需要将堆变成一个最大堆(这样就与已经是最小堆的情况形成了矛盾)! 3、实际上lucene在实现的时候使用了一些小技巧:由于第1步我们采用了最小堆,到第2步的时候与第1步产生了矛盾,所以我们通过最小堆不能生成前N个最小的序列了。反过来我们可以实现保留最大的前N个数值,因为每次插入新元素时只需将队列中最小的元素给替换掉! 实际上lucene在实现堆的时候,数组下标是从1开始的(这是因为在计算父子节点的下标时可以少一些加法运算)。 来源: oschina 链接: https://my.oschina.net/u/1268334/blog/3143061

优先级队列

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-14 17:35:57
优先级队列 - 简书一、定义 优先级队列有很多种实现方式。其中使用 “堆” 来实现 “优先队列” 是最常见的,堆的底层是完全二叉树的形式。 上述是一个小顶堆(最小堆)的示意图 最小堆是一种经过排序的完全... 一、定义 优先级队列有很多种实现方式。其中使用 “堆” 来实现 “优先队列” 是最常见的,堆的底层是完全二叉树的形式。 1-0 堆的示意图 上述是一个小顶堆(最小堆)的示意图 最小堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。 二、API 2-0 大顶堆的 API 定义 2.1 上浮和下沉 堆的操作中,最重要的就是堆元素的上浮和下沉操作: 上浮(siftup) 在堆中插入元素后(完全二叉树的最右下方插入),需要进行上浮操作,重新使得堆有序。 2-1-1 大顶堆上浮元素 private void swim(int k) { while (k > 1 && (a[k]>a[k/2])) { exch(k, k/2); k = k/2; } } 下沉(siftdown) 当删除一个堆元素(堆顶)时,首先将堆顶元素与最右下方元素交换,然后删除。此时堆顶元素需要进行下沉操作,重新使得堆有序。 2-1-2 大顶堆下沉元素 private void sink(int k) { while (2*k <= n) { int j = 2*k; if

最短路径算法

陌路散爱 提交于 2019-12-09 18:09:23
单源最短路径问题 问题描述:给你一个顶点做源点,你想要知道,如何从源点到达其他所有点的最短路径。 OK,这个问题看起来没什么用。我们一般想知道的是A点到B点的最短路径,这个单源最短路径问题告诉我们A点到所有点的最短路径,会不会计算过多了呢? 有趣的是,解决A点到B点的最短路径算法不会比单源最短路径问题简单,我们所知的求A点到B点的最短路径算法就是求A点到任何点的最短路径。我们除了这样做,好像也没什么好办法了。 Dijkstra算法 基本原理: 每次新扩展一个距离最短的点,更新与其相邻的点的距离。当所有边权都为正时,由于不会存在一个距离更短的没扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。不过根据这个原理,用Dijkstra求最短路的图 不能有负权边 ,因为扩展到负权边的时候会产生更短的距离,有可能就破坏了已经更新的点距离不会改变的性质。 适用条件与限制: 有向图 和 无向图 都可以使用本算法,无向图中的每条边可以看成相反的两条边。 用来求最短路的图中不能存在负权边。(可以利用拓扑排序检测) 算法流程: 在以下说明中,s为源,w[u,v]为点u和v之间的边的长度,结果保存在dist[] 初始化:源的距离dist[s]设为0,其他的点距离设为 正无穷大 ,同时把所有的点的状态设为没有扩展过。 循环n-1次: 在没有扩展过的点中取距离最小的点u

海量数据面试题整理

本小妞迷上赌 提交于 2019-12-08 19:06:28
1. 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url? 方案1:可以估计每个文件安的大小为50G×64=320G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。 s 遍历文件a,对每个url求取 ,然后根据所取得的值将url分别存储到1000个小文件(记为 )中。这样每个小文件的大约为300M。 s 遍历文件b,采取和a相同的方式将url分别存储到1000各小文件(记为 )。这样处理后,所有可能相同的url都在对应的小文件( )中,不对应的小文件不可能有相同的url。然后我们只要求出1000对小文件中相同的url即可。 s 求每对小文件中相同的url时,可以把其中一个小文件的url存储到hash_set中。然后遍历另一个小文件的每个url,看其是否在刚才构建的hash_set中,如果是,那么就是共同的url,存到文件里面就可以了。 方案2:如果允许有一定的错误率,可以使用Bloom filter,4G内存大概可以表示340亿bit。将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。 2. 有10个文件,每个文件1G

17道经典海量数据面试题整理

余生长醉 提交于 2019-12-08 18:49:53
1. 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url? 方案1:可以估计每个文件安的大小为50G×64=320G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。 s 遍历文件a,对每个url求取 ,然后根据所取得的值将url分别存储到1000个小文件(记为 )中。这样每个小文件的大约为300M。 s 遍历文件b,采取和a相同的方式将url分别存储到1000各小文件(记为 )。这样处理后,所有可能相同的url都在对应的小文件( )中,不对应的小文件不可能有相同的url。然后我们只要求出1000对小文件中相同的url即可。 s 求每对小文件中相同的url时,可以把其中一个小文件的url存储到hash_set中。然后遍历另一个小文件的每个url,看其是否在刚才构建的hash_set中,如果是,那么就是共同的url,存到文件里面就可以了。 方案2:如果允许有一定的错误率,可以使用Bloom filter,4G内存大概可以表示340亿bit。将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。 2. 有10个文件,每个文件1G

海量数据处理专题4——堆

被刻印的时光 ゝ 提交于 2019-12-08 18:45:04
【什么是堆】 概念:堆是一种特殊的二叉树,具备以下两种性质 1)每个节点的值都大于(或者都小于,称为最小堆)其子节点的值 2)树是完全平衡的,并且最后一层的树叶都在最左边 这样就定义了一个最大堆。如下图用一个数组来表示堆: 那么下面介绍二叉堆:二叉堆是一种完全二叉树,其任意子树的左右节点(如果有的话)的键值一定比根节点大,上图其实就是一个二叉堆。 你一定发觉了,最小的一个元素就是数组第一个元素,那么二叉堆这种有序队列如何入队呢?看图: 假设要在这个二叉堆里入队一个单元,键值为2,那只需在数组末尾加入这个元素,然后尽可能把这个元素往上挪,直到挪不动,经过了这种复杂度为Ο(logn)的操作,二叉堆还是二叉堆。 那如何出队呢?也不难,看图: 出队一定是出数组的第一个元素,这么来第一个元素以前的位置就成了空位,我们需要把这个空位挪至叶子节点,然后把数组最后一个元素插入这个空位,把这个“空位”尽量往上挪。这种操作的复杂度也是Ο(logn)。 【适用范围】 海量数据前n大,并且n比较小,堆可以放入内存 【基本原理及要点】 最大堆求前n小,最小堆求前n大。方法,比如求前n小,我们比较当前元素与最大堆里的最大元素,如果它小于最大元素,则应该替换那个最大元 素。这样最后得到的n个元素就是最小的n个。适合大数据量,求前n小,n的大小比较小的情况,这样可以扫描一遍即可得到所有的前n元素,效率很高。

海量数据处理专题(五)——堆

蓝咒 提交于 2019-12-08 18:44:18
转: http://blog.redfox66.com/post/mass-data-topic-5-heap.aspx 【什么是堆】 概念:堆是一种特殊的二叉树,具备以下两种性质 1)每个节点的值都大于(或者都小于,称为最小堆)其子节点的值 2)树是完全平衡的,并且最后一层的树叶都在最左边 这样就定义了一个最大堆。如下图用一个数组来表示堆: 那么下面介绍二叉堆:二叉堆是一种完全二叉树,其任意子树的左右节点(如果有的话)的键值一定比根节点大,上图其实就是一个二叉堆。 你一定发觉了,最小的一个元素就是数组第一个元素,那么二叉堆这种有序队列如何入队呢?看图: 假设要在这个二叉堆里入队一个单元,键值为2,那只需在数组末尾加入这个元素,然后尽可能把这个元素往上挪,直到挪不动,经过了这种复杂度为Ο(logn)的操作,二叉堆还是二叉堆。 那如何出队呢?也不难,看图: 出队一定是出数组的第一个元素,这么来第一个元素以前的位置就成了空位,我们需要把这个空位挪至叶子节点,然后把数组最后一个元素插入这个空位,把这个“空位”尽量往上挪。这种操作的复杂度也是Ο(logn)。 【适用范围】 海量数据前n大,并且n比较小,堆可以放入内存 【基本原理及要点】 最大堆求前n小,最小堆求前n大。方法,比如求前n小,我们比较当前元素与最大堆里的最大元素,如果它小于最大元素,则应该替换那个最大元 素

使用最小堆解决海量数据数据中求TopK最大的几个数问题

邮差的信 提交于 2019-12-08 18:39:20
前几天面试遇到了这么一个问题: 求一亿个数据中最大的100个数. 这个问题一脸懵逼我. 后来查了资料说使用HASH函数以及分治的思想来解决.将这1亿个数根据HASH去重然后根据hash值分别存储到1000个分区内,然后每个分区都使用一个容量为100的最小堆得到每个区最大的100个数. 最后将1000个分区内得到的最小堆再合并处理即可. 这里主要是最小堆的问题. 怪我基础差,面试过后又补了补最小堆的知识.参考网上,写了一个最小堆的Demo来巩固知识. 有些概念得知道,一般最小堆都是使用数组来存储的. 如果一个子节点下标位置为x,那么他的父类位置即为(x-1)/2 如果一个父节点下标位置为y,那么他的右节点位置为(x+1)<<1,左节点位置为(x+1)<<1. 注意: (数组长度)/2-1代表下标最大的那个有子节点的父节点位置. 因为最后一个节点位置为(数组长度-1),然后其父类节点位置为(数组长度-2)/2,即为(数组长度)/2-1 //最小堆 class MinHeap{ //最小堆维持的大小 private int[] data; public MinHeap(int[] data){ this.data = data; buildHeap(); } //建立最小堆 private void buildHeap(){ for(int i=(data.length)/2-1;i>

海量数据中的TopK问题

青春壹個敷衍的年華 提交于 2019-12-08 18:34:14
1. 抛出问题 在大规模数据处理中,经常会遇到的一类问题:在海量数据中找出出现频率最好的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为top K问题。例如,在搜索引擎中,统计搜索最热门的10个查询词;在歌曲库中统计下载最高的前10首歌等。 针对top K类问题,通常比较好的方案是分治+Trie树/hash+小顶堆(就是上面提到的最小堆),即先将数据集按照Hash方法分解成多个小数据集,然后使用Trie树活着Hash统计每个小数据集中的query词频,之后用小顶堆求出每个数据集中出现频率最高的前K个数,最后在所有top K中求出最终的top K。 eg:有1亿个浮点数,如何找出其中最大的10000个? 2. 如何解决 1)全局排序法 这是最容易想到的方法,将数据全部排序,然后在排序后的集合中进行查找,最快的排序算法的时间复杂度一般为O(nlogn),如快速排序。 但是在32位的机器上,每个float类型占4个字节,1亿个浮点数就要占用400MB的存储空间,对于一些可用内存小于400M的计算机而言,很显然是不能一次将全部数据读入内存进行排序的。其实即使内存能够满足要求(我机器内存都是8GB),该方法也并不高效,因为题目的目的是寻找出最大的10000个数即可,而排序却是将所有的元素都排序了,做了很多的无用功。 2)局部淘汰法 该方法与全局排序法类似