是否可以实现最大和最小堆的二进制堆?

时间:2015-07-23 02:43:50

标签: c++ algorithm data-structures priority-queue binary-heap

我正在尝试实现具有最小堆和最大堆功能的二进制堆(优先级队列)。它需要有insert(value)extractMin()extractMax()方法。 extract方法从堆中删除值并返回值。

我最初使用两个数组,称为minHeapmaxHeap,一个用于将数据存储在最小堆结构中,另一个用于将相同数据存储在最大堆结构中。因此,当我调用extractMin()时,它会移除并返回minHeap中的值。然后我必须从maxHeap中移除该值(反之亦然,如果我调用extractMax()),以便在两个堆中保持数据集相同。而且由于堆顺序属性,我保证我会在另一个堆的叶子中找到该值。在另一个堆中搜索该值会导致时间复杂度为O(n)或更准确地为O(n / 2),因为我只会搜索叶子。更不用说,删除值后恢复堆的percolatingDown()percolatingUp()方法已经是O(log n);总的来说,提取方法是O(n)。问题是,我需要提取方法为O(log n)。

有没有更好的方法来解决这个问题?

我也想到了这个想法,但想知道你们首先想到的是什么。

我刚刚完成了对“中间堆”的编码,方法是将较小的一半数据放在最大堆中,将较大的一半放在最小堆中。通过该结构,我能够轻松检索给定值集的中值。我正在考虑使用一种类似的结构,将较小的一半数据放在最小堆中,将较大的一半放在最大堆中,并使用所有值的平均值(而不是中值)作为决定因素的决定因素。在调用insert(value)时将值放在最大或最小堆中。我认为这可能有效,因为提取方法将保持为O(log n)。

4 个答案:

答案 0 :(得分:4)

简单的方法就是使用二叉搜索树,正如M. Shaw所建议的那样。

如果你需要在二进制堆之上构建它,那么在每个堆中,与每个元素一起,将元素的位置存储在另一个堆中。每次在一个堆中移动元素时,您都可以直接转到其他堆中的位置并更新它。执行delete-min或delete-max时,不需要在另一个堆中进行昂贵的线性扫描。

例如,如果将CREATE TABLE FinishedOrderCountByUser( UserId INT, Sex CHAR(1), CountOfFinished INT ) INSERT INTO FinishedOrderCountByUser(UserId, Sex, CountOfFinished) SELECT u.id, u.sex, ISNULL(COUNT(o.state), 0) as CountOfFinished FROM users u LEFT JOIN orders o ON o.id_user = u.id AND o.state = 'finished' GROUP BY u.id, u.sex 存储为std::pair作为元素值而将first存储为另一个堆中的位置,则在更新它们时更换最小堆中的两个元素max-heap中的对应部分可能如下所示:

second

答案 1 :(得分:3)

您可以为堆元素创建一个哈希表,由两个堆共享。该表由heap元素的值索引。散列桶的值可以是由minHeap和maxHeap中的数组索引组成的结构。

这种方法的好处是它是非侵入性的,这意味着堆元素的结构保持不变。而且你不必并排创建堆。您可以使用通常的堆创建过程一个接一个地创建。

如,

struct tIndex
{
   // Array index of the element in two heaps respectively
   size_t minIndex;
   size_t maxIndex;
};

std::unordered_map<int, tIndex> m;

enter image description here

请注意,对堆的任何更改都可能会更改现有元素的基础数组索引。因此,当您添加/删除元素或交换两个元素时,您可能需要相应地更新其在哈希表中的数组索引。

答案 2 :(得分:0)

你关闭了。诀窍是使用另一个间接层。将键保持在数组K [i]中并仅将索引i存储在堆中。同时保留两个反向映射:一个用于最大堆,一个用于最小值。反向映射是整数R的数组,使得R [i]是密钥K [i]的索引i的最小(或最大)堆中的位置。换句话说,如果M [j]是最小(或最大)堆,那么R [M [j]] = j;现在,无论何时进行筛选操作以在堆中移动元素,都必须同时更新相应的反向映射。实际上它就像上面的关系一样工作。在更改堆元素M [j] = z的每个步骤中,也更新反向映射R [z] = j;这会使运行时间仅增加很小的常数因子。现在要从堆中删除K [i],你可以在恒定时间内找到它:它在M [R [i]]处。将它移到根部并将其移除。

我知道这是有效的(在常数时间内找到要删除的堆对象),因为我已经将它作为更大算法的一部分实现了。查看https://github.com/gene-ressler/lulu/blob/master/ext/lulu/pq.c。较大的算法用于地图标记合并:https://github.com/gene-ressler/lulu/wiki

答案 3 :(得分:0)

http://www.geeksforgeeks.org/a-data-structure-question/

Min-Max堆我会说是#34; user2357112&#34;如果最频繁的操作是findMin和findMax。如果我们真的不想要一个完全有序的数据结构,BST可能是一种矫枉过正,上面是一个部分有序的数据结构。请参阅上面发布的链接。