二进制最小堆中的增加键和减少键


16

在许多关于二进制堆的讨论中,通常仅将减小键列为最小堆的受支持操作。例如,CLR第6.1章和此Wikipedia页面。为什么通常不会为最小堆列出增加密钥?我想可以通过将增加的元素(x)迭代替换为其最小的子元素来在O(height)中做到这一点,直到其子元素都不大于x为止。

例如

IncreaseKey(int pos, int newValue)
{
   heap[pos] = newValue;
   while(left(pos) < heap.Length)
   {
      int smallest = left(pos);
      if(heap[right(pos)] < heap[left(pos)])
         smallest = right(pos);
      if(heap[pos] < heap[smallest])
      { 
         swap(smallest, pos);
         pos= smallest;
      }
      else return;
   }   
}

以上正确吗?如果没有,为什么?如果是,为什么没有列出最小堆的增加密钥?


1
阅读完所有答案后,我会说这是一个奇怪的遗漏,这可能是由于Dijkstra算法在历史上首次使用min-heap引起的。
maaartinus 2014年

3
当然,您总是可以使用删除操作和插入操作来实现增加键,并且删除本身可以通过减少键(至-∞)和删除分钟来实现。
davmac '16

@maaartinus评论是正确的答案。
最大

Answers:


6

您建议的算法只是heapify。确实,如果您增加了最小堆中元素的值,然后对其子树进行堆放,那么最终您将获得合法的最小堆。


那么为什么不CLR或Wikipedia列出增加密钥成为受支持的操作呢?有点误导我以为不可能在最小堆中实现
GatotPujo

我同意这是一种误导,但我认为算法没有任何错误。
Shaull

5

未列出您的操作的原因是,一个操作人员不只是对可以使用某种数据结构轻松实现的所有操作感兴趣,而是另一种方式。给定一组操作,实现这些操作的最有效方法(就空间和时间而言)是什么。(但我稍后会添加更多内容)

二进制堆实现抽象数据结构优先级队列,该队列要求操作is_empty,add_element(具有优先级的键),find_min和delete_min。更高级的队列还允许人们降低密钥的优先级(在min_heap中),甚至增加它的优先级。实际上,您已经给出了一个实现。

两句话。您的操作用在heapify函数中,该函数可有效地从数组构造一个堆。在heapify中,将重复您的操作(从最后一个键开始)。

然后,最重要的是,您的代码使用节点的位置。对于欺骗的纯数据结构优先级队列。该数据结构要求执行给定密钥的特定操作。因此,为了降低或增加元素的优先级,您首先必须找到它。我认为这是未列出的主要原因。


1
感谢您的解释。但是,在CLR减小键中也将位置作为节点作为参数。
GatotPujo 2013年

你是对的。在CLRS的第6.5节中的优先级队列的定义中,我找不到这种不对称的原因。注意在本章的应用Heapsort中不使用增加键。似乎增加和减少之间的不对称性仅与Dijkstra算法中使用数据结构的方式有关。在那儿(使用最小堆),一些选定的节点可能会变得更紧急,并在堆中“上移”。
Hendrik

0

我认为首先要考虑的是什么是支持的操作?

“使用特定的固定键插入值”(例如,对于取自整数域的键,以key = 3插入)是否对应于最小堆的支持操作?

不可以,因为该操作可以使用更通用的受支持的操作轻松实现。同样,可以通过现有insert操作一次插入2个元素。

另一方面,insert只能通过公开实现细节来定义操作。维基百科页面上列出的操作几乎相同heapify,但可以通过一系列序列来实现insert

换句话说,在类型上提供了基本操作,这些基本操作紧密绑定到实现细节上才能使其正常运行,而其他操作则不遵守该规则,因此可以组合使用规范的。

考虑到该定义,您是否认为可以在不损失性能的情况下,以排他性的方式与其他受支持的操作一起实施增加键?如果是这样,则上述定义不支持该操作,否则,您可能是对的。

据我所知,我提供的支持的操作的定义是我的。它不是正式的,因此需要讨论(尽管对我来说似乎很清楚)。但是,如果有人可以提供一个明确,明确地定义数据类型支持的操作的源,或者至少比我的定义更好的术语,我会很高兴(该定义在CLR中给出吗?我没有副本) )。

我的第二点是关于如何定义优先级队列(即二进制堆的存在理由)。increase_key该数据类型是否必须进行必要的操作,即正确使用?

如您所见,我的观点全与定义有关。我并没有真正回答您的问题,只是提供了一些指示,因此欢迎您进行改进。


1
如果我想基于最近最少使用的对象维护对象的优先级队列(例如,以便我可以轻松删除最近最少使用的对象),则可能是一个示例用例。我可以使用最小访问量作为最后访问日期。如果访问对象,则需要增加其密钥。
GatotPujo 2013年

很好的一点。我的观点似乎有些局限。确实,@ HendrikJan答案带来了很好的解释。
didierc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.