std :: priority_queue与迭代器到std :: map的元素 - 无效堆

时间:2014-10-25 17:10:10

标签: c++ c++11 stl

我还没有粘贴所有代码,因为它可能太复杂了。我会先尝试写下我的问题。

我尝试实现一些算法。我需要容器(键值)与键访问(如std::map),我需要快速访问get(和remove)元素具有最大值。

所以我使用std::map<key, value> myMap,我有std::priority_queue<std::map<key, value>::iterator> myQueue

    typedef std::map<cv::Point, double>::iterator mapIter;

    class mycomparison
    {
        public:
        bool operator() (mapIter lhs, mapIter rhs) const
        {
            return lhs->second > rhs->second; // (*)
        }
    };

    std::priority_queue<mapIter, std::vector<mapIter>, mycomparison> myQueue;

     // I fill `myQueue` with iterator to every element of `myMap` ...

    while (!myQueue.empty())
    {
        mapIter iter = myQueue.top();
        // ...
        // ...
        if (myMap[key1] > myMap[iter->first] + someValue)
            myMap[key1] = myMap[iter->first] + someValue; // (**)
        myQueue.pop();
    }

调试时遇到问题。我在myQueue.pop() - Invalid heap期间出错了。当我用(**)评论时。没有错误。

有什么问题?这是不安全的操作吗?

或许错误在另一条线上?

comparision(*)怎么样?当我返回return lhs->second > rhs->second;一切看起来都不错。但我需要&gt;操作。

我无法理解为什么会出错。我花了很多时间。有什么想法吗?

我认为这是我这个问题的重要代码...

1 个答案:

答案 0 :(得分:3)

问题很简单,地图中值的赋值会导致堆条件被违反:由于您在优先级队列中存储的元素不是值,而只是引用值,因此更改元素可能会破坏必要条件!仅仅因为更改元素的键并不意味着优先级队列将重新排列优先级队列的结构。

您似乎正在尝试实现Dijkstra的最短路径算法,该算法在检测到已到达节点的路径较短时需要更新节点的密钥。要处理这些更新,您需要以某种方式引用优先级队列中需要更新的节点。通常使用Fibonacci-heap来有效地实现这种算法,这也具有基于节点而不是基于数组的优点:F​​ibonacci-heap中的元素保留在内存中,这样可以很容易地保持对节点的引用。调整。

可以使用d-heap实现类似的逻辑,但std::priority_queue<T>不提供此功能。使用具有固定节点位置的d堆的方法是存储辅助数组,该数组具有指向d堆中的节点的指针,其提供用于更新的密钥。当移动d堆中的元素时,辅助数组中的相应指针也会更新。这些更新大大减慢了处理速度,这是因为它们在不需要时不会完成,例如,std::priority_queue<T>可以用于堆排序。