使用hashmap实现优先级队列

时间:2014-06-23 17:52:42

标签: java hashmap priority-queue

这可能是一个非常天真的问题,或者没有意义。但我真的很困惑优先级队列的实现。  为什么我们不能将带有键的hashmap作为优先级和值用作具有该优先级的数据。 我在这里缺少一些基本的东西。 例如: 如果A的优先级为1,则B为3,c为4 我们可以简单地将1,3,4作为键,将A,B,C作为hashmap的值分别用于优先级队列实现。 请清除我的逻辑

4 个答案:

答案 0 :(得分:4)

该实现的问题在于它没有利用HashMap功能轻松访问给定密钥的任何元素。由于你正在建立一个队列,你以后不会优先考虑优先级1,3,4,而只需要找到地图的最高优先级,不得不完全迭代它!

地图的工作原理如下:它创建了一个巨大的数组,在所有位置都有空值(非常,非常大)。然后,它使用公式来获取您的键,通常是字符串或字符串表示并将其转换为数字。一个简单的方法是将每个字母的char代码相加,尽管这对于地图来说是一个糟糕的选择,你可以稍后查找原因。然后,它用数组的模数(余数)大小(例如,Java中的n%大小)来限制该数字,以便它成为数组中的有效位置,然后将元素放在那里。这样,进行密集搜索非常容易,因为您不需要搜索,您确切知道每个元素的位置。

因此,使用Map实现队列将是内存密集型的,没有HashMap搜索的明显优势。此外,迭代它非常非常昂贵,因为你需要遍历一个巨大的数组并忽略空值;你不确定实际值在哪里。想象一下,在你的例子中,优先级从0到100.即使你永远不会有100个任务,你也会有100个位置数组进行迭代,如果有一个具有该优先级的任务,则检查每个位置。

更好的方法是使用简单列表并将优先级存储在数据中。假设优先级不随时间变化,您只需要在添加时迭代一次,找到正确的位置,并始终访问第一个(或最后一个)元素,即具有已知最高优先级的元素。

在性能最后的注释中,最好在添加时进行迭代,即使您添加了与搜索完全相同的时间。因为当你搜索最高优先级时,你需要每次都结束,因为最后一个元素可能是更大的元素。请注意,即使您的键是数字字符串或整数,HashMap也不会以整齐的新月顺序存储您的项目。它专门设计为,以避免冲突(两个相似的对象具有相同的密钥,因此需要将列表添加到大数组的特定位置)。但是,当您添加时,假设您的列表已经订购,您只需要进行迭代,直到到达正确的目的地。

答案 1 :(得分:2)

当您尝试迭代HashMap时,您将获得一个奇怪的订单。 HashMap s(或任何地图)没有保证的遍历顺序,因此您无法"订购"队列以有效的方式。

您当然可以查询所有密钥,订购该列表,并按顺序获取值,但与替代方案相比效率非常低(您已经在O(n ^ 2)处长度没有做额外工作的钥匙)

答案 2 :(得分:2)

长话短说,这一切都归结为HashMap没有订购的事实,所以你最终还是需要一些外部机制来弄清楚什么是&#39} s && #34;下一个"在队列中。

例如,假设您输入了条目

[1, "A"]
[3, "B"]
[4, "C"]

如果您只有HashMap,那么就没有可靠的方法来确定1是"首先"没有遍历每个键,因为内部的键可能是:

[1, "A"]
[3, "B"]
[4, "C"]

[3, "B"]
[4, "C"]
[1, "A"]

[3, "B"]
[1, "A"]
[4, "C"]

等等。

来自HashMap javadoc

  

此课程不保证地图的顺序;特别是,它不保证订单会随着时间的推移保持不变。

所以使用HashMap确实没有意义,因为无论如何你必须做的额外工作最终会使得HashMap效率低于堆。


现在,如果真的想要使用HashMap,您可以:

  • 抓住EntrySet,按键排序,然后获取第一个值。如果那是时间你需要获取第一个值,那就没关系,但这种情况很少发生。一旦你改变地图并需要再次进行,效率就会比常规堆更差。

  • 使用一些外部机制(例如ArrayList或其他东西来跟踪密钥,可能会将其作为插入值的一部分进行排序。此时也可以跳过HashMap并实现堆"通常"但是,因为否则你基本上做同样的事情,但是增加了在两者之间拆分数据的复杂性ArrayListHashMap

所以最后,额外的工作并不值得。

答案 3 :(得分:0)

priorityQueue使您的数据保持排序并保持该结构,如果要遍历priorityQueue,它将以一致地实现其构造函数的方式返回数据。 HashMap不会保留插入顺序。如果您尝试从哈希图中返回所有元素,则会得到不一致的结果。

除此之外,priorityQueue使用最小/最大堆来保持数据有序,因此,任何插入/删除操作都是Log(n),因为它必须比较log(n)级别的节点以维护priorityQueue属性。其中n是队列中的数据数。

也许您可以使用的是linkedHashMap来保留数据的顺序,因为它使用双链表结构。但是,对于关键操作(如getMax()),运行时性能比PriorityQueue差。 priorityQueue将在O(log(n))时间完成操作,而linkedHashMap将花费O(n)时间,因为现在您必须遍历整个linkedList以找到最大值/最小值。

希望有帮助