简体   繁体   中英

std::priority_queue with iterators to elements of std::map - invalid heap

I haven't pasted all code because it could be too much complicated. I'll try to write about my problem first.

I try to implement some algorithm. I need container (key-value) with with access by key (like std::map ) and I need to fast access to get (and remove) element with maximum value.

So I use std::map<key, value> myMap and I have 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();
    }

I have problem with debugging it. I have an error during myQueue.pop() - Invalid heap . When I commented line with (**). There is no error.

What is wrong? Is it unsafe operation?

Or maybe mistake is in another line?

How about comparision (*)? When I return return lhs->second > rhs->second; Everything looks OK. But I need > operation.

I couldn't understand why there is an error. I spent many hours. Any idea?

I think it's all my important code for this question...

The problem is simply that the assignment to the values in the map causes the heap condition to become violated: since the elements you are storing in the priority queue are not the values but only reference the values, changing the elements can break the necessary conditions! Just because you change the key of an element doesn't mean that the priority queue will rearrange the structure of the priority queue.

It seems you are trying to implement Dijkstra's shortest path algorithm which requires updating the key of a node when it is detected that there is a shorter path to an already reached node. To deal with these updates you'll need to somehow reference the node in the in the priority queue which needs to be updated. Conventionally a Fibonacci-heap is used to implement this algorithms efficiently which also has the advantage that it is node based rather than array based: elements in a Fibonacci-heap stay put in memory making it easy to keep a reference to the node which can then be adjusted.

A similar logic can be implemented with a d-heap but std::priority_queue<T> doesn't provide this functionality. The approach to use a d-heap with fixed node positions is to store an auxiliary array with pointers to the nodes in the d-heap which provides the keys used for updates. When elements in the d-heap are moved the corresponding pointers in the auxiliary array are also updated. These updates slow down the processing substantially which is the reason they are not done when they are not needed, eg, for std::priority_queue<T> which can be used for heap-sort.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM