【问题标题】:How to implement O(1) deletion on min-heap with hashtable如何使用哈希表在最小堆上实现 O(1) 删除
【发布时间】:2013-08-21 17:18:27
【问题描述】:

在某处阅读以下语句:

额外的哈希表可用于快速删除 最小堆。

问题>如何结合priority_queueunordered_map实现上面的思路?

#include <queue>
#include <unordered_map>
#include <iostream>
#include <list>
using namespace std;

struct Age
{
  Age(int age) : m_age(age) {}
  int m_age;  
};

// Hash function for Age
class HashAge {
  public:
   const size_t operator()(const Age &a) const {
     return hash<int>()(a.m_age);
   }
};

struct AgeGreater
{
  bool operator()(const Age& lhs, const Age& rhs) const {
    return lhs.m_age < rhs.m_age;
  }
};

int main()
{
  priority_queue<Age, list<Age>, AgeGreater> min_heap;          // doesn't work
  //priority_queue<Age, vector<Age>, AgeGreater> min_heap;

  // Is this the right way to do it?
  unordered_map<Age, list<Age>::iterator, HashAge > hashTable;     
}

问题>我无法完成以下工作:

priority_queue<Age, list<Age>, AgeGreater> min_heap;          // doesn't work

我必须使用列表作为容器 b/c 列表的迭代器不受插入/删除的影响 (Iterator invalidation rules)

【问题讨论】:

  • 我想我想知道您为什么要使用优先级队列来实现最小堆,因为我已经习惯了相反的方式。
  • 你在哪里读到这个?
  • "一个额外的哈希表可用于在最小堆中快速删除。"虽然这可能是真的,也可能不是,但该声明并不是专门指priority_queueunordered_map,我严重怀疑它们是否可以以任何有效的方式一起使用,更不用说评论讨论的方式了。跨度>
  • 你是对的,这本书没有提到priority_queue或unordered_map。在这里,我只是想根据这个想法在c++中实现这个想法。

标签: c++ algorithm


【解决方案1】:

您不能使用提供的 priority_queue 数据结构来执行此操作:

在优先级队列中,你不知道元素存储在哪里,因此很难在恒定时间内删除它们,因为你找不到元素。但是,如果您维护一个哈希表,其中存储在哈希表中的优先级队列中每个元素的位置,那么您可以快速找到并删除一个项目,尽管我希望在最坏的情况下使用 log(N) 时间,而不是恒定的时间。 (我不记得如果你得到摊销的常数时间。)

为此,您通常需要滚动自己的数据结构,因为每次在优先级队列中移动项目时,您都必须更新哈希表。

我在这里有一些示例代码:

http://code.google.com/p/hog2/source/browse/trunk/algorithms/AStarOpenClosed.h

它基于较旧的编码风格,但它可以胜任。

举例说明:

/**
 * Moves a node up the heap. Returns true if the node was moved, false otherwise.
 */
template<typename state, typename CmpKey, class dataStructure>
bool AStarOpenClosed<state, CmpKey, dataStructure>::HeapifyUp(unsigned int index)
{
        if (index == 0) return false;
        int parent = (index-1)/2;
        CmpKey compare;

        if (compare(elements[theHeap[parent]], elements[theHeap[index]]))
        {
                // Perform normal heap operations
                unsigned int tmp = theHeap[parent];
                theHeap[parent] = theHeap[index];
                theHeap[index] = tmp;
                // Update the element location in the hash table
                elements[theHeap[parent]].openLocation = parent;
                elements[theHeap[index]].openLocation = index;
                HeapifyUp(parent);
                return true;
        }
        return false;
}

if 语句中,我们对堆执行正常的heapify 操作,然后更新哈希表(openLocation) 中的位置以指向优先级队列中的当前位置。

【讨论】:

  • 你得到了哈希表的摊销常数,但是如果不破坏优先队列的实现,优先队列不能比log n做得更好
  • ... 这可能会破坏其他操作的性能(例如:插入)..
  • ... 对于大多数声称 O(1) 进行插入(或删除)的变体,它带有一个 巨大 常数因子,可以实现真实世界的性能比使用简单的二叉堆更糟糕。
猜你喜欢
  • 2023-02-07
  • 1970-01-01
  • 2014-05-25
  • 2019-05-09
  • 1970-01-01
  • 2011-12-27
  • 2016-11-12
  • 1970-01-01
  • 2013-09-26
相关资源
最近更新 更多