Hi,

I need to create a stack with a key and for each key one or more instances of a data structure associated. A multi map seems to be best suited for this.

However, I don't know how I could extract an element with the maximum key value whithout knowing that max value. Is that possible with a multi-map ? Is there a special iterator for this ?

thanks for your help !!

matt-

Dani AI

Generated

As described, the goal is a keyed collection (distance) that can hold multiple points but enforces coordinate uniqueness and lets the largest-distance element be extracted quickly. There are two pragmatic patterns that cover the common needs mentioned in the thread.

A balanced-tree container such as std::multimap gives ordered traversal and the max element is available without knowing the value: use rbegin() or prev(end()) to read the largest key and then erase that iterator to remove it. This is convenient when ordered iteration or erase-by-iterator is needed.

// access & remove largest in a multimap<K,V> mm
auto it = std::prev(mm.end());
auto maxKey = it->first;
auto val = it->second;
mm.erase(it);

For fast top-only extraction the heap (std::priority_queue) that suggested is ideal. To enforce coordinate-uniqueness, keep a separate lookup keyed on coordinates rather than relying on the heap itself. An unordered_set with a small custom hash and operator== is efficient for that:

struct Coord { int x,y,z; bool operator==(Coord const& o) const noexcept { return x==o.x && y==o.y && z==o.z; } };
struct CoordHash { size_t operator()(Coord const& c) const noexcept {
  return ((size_t)c.x*73856093u) ^ ((size_t)c.y*19349663u) ^ ((size_t)c.z*83492791u);
} };
std::unordered_set<Coord,CoordHash> seen;

Tradeoffs and a common pattern: heap gives O(1) top and O(log n) push/pop but does not support efficient arbitrary erase; multimap/set give O(log n) insert/erase and ordered traversal. If distances can change, use the double-structure (map of current best distances + heap) and lazy-delete stale heap entries on pop:

while (!pq.empty()) {
  auto [d,c] = pq.top();
  if (current[c] != d) { pq.pop(); continue; } // stale
  // process valid top
}

A final caution: any ordering comparator must implement a strict weak ordering. The &&-style comparator in the example reply is incorrect; prefer lexicographic compare or std::tie. In short: for fast top-only semantics use priority_queue + an auxiliary unordered_set/map for uniqueness; for ordered iteration or direct-iterator erasure use multimap and read the max with rbegin/prev(end()).

Recommended Answers

All 6 Replies

It sounds like you want a priority_queue.

Well, the thing is that I need the association with another data structure for a given key, but the key being needed for sorting. Practically, I have a distance measurement, and an x,y,z coordinate associated to it. several x,y,z points can have the same distance measurement, but I need the sorting only on the key.

Is there a thing like a multi-priority-queue ?

>Is there a thing like a multi-priority-queue ?
That's what a priority_queue is. It's an adapter around a sequence container such as vector or deque that implements a heap. Duplicate keys are allowed, and you can do what the map does and use a pair as the value. For example, if you need to extract the largest of a collection keyed on the distance measurement, but the distance measurement is independent from the coordinates, you could set up your priority_queue like this:

#include <cstdlib>
#include <iostream>
#include <queue>
#include <utility>

using namespace std;

struct coord {
  int x, y, z;

  coord ( int ix, int iy, int iz )
    : x ( ix ), y ( iy ), z ( iz )
  {}
};

ostream& operator<< ( ostream& out, const coord& c )
{
  return out<<'('<< c.x <<','<< c.y <<','<< c.z <<')';
}

bool operator< ( const pair<int, coord>& a,
  const pair<int, coord>& b )
{
  return a.first < b.first;
}

int main()
{
  priority_queue<pair<int, coord> > pq;

  for ( int i = 0; i < 10; i++ )
    pq.push ( make_pair ( rand() % 10, coord ( i + 1, i + 2, i + 3 ) ) );

  while ( !pq.empty() ) {
    std::cout<< pq.top().first <<" -- "<< pq.top().second <<'\n';
    pq.pop();
  }
}

well ... looks like you coded my problem !

Thanks alot !!!

Now, one more question : is there an easy way to avoid duplicate insertions ? i.e. same key (distance value) and x,y,z coordinates ? The thing is an x,y,z coordinate should be unique.

Member Avatar for Member #36984

i was a bit confused by the title lol :lol:

look at www.multimap.com!

heh heh heh...

>The thing is an x,y,z coordinate should be unique.
That's more difficult. If you need that kind of flexibility while still having priority queue semantics, you can eschew the adapter entirely and go manual with the make_heap, push_heap, pop_heap functions, and your desired scheme for removing duplicates. But a smarter solution would use two data structures, one for your priority queue and one for checking duplicates, such as a set:

#include <cstdlib>
#include <iostream>
#include <set>
#include <queue>
#include <utility>

using namespace std;

struct coord {
  int x, y, z;

  coord ( int ix, int iy, int iz )
    : x ( ix ), y ( iy ), z ( iz )
  {}
};

ostream& operator<< ( ostream& out, const coord& c )
{
  return out<<'('<< c.x <<','<< c.y <<','<< c.z <<')';
}

bool operator< ( const coord& a, const coord& b )
{
  return a.x < b.x && a.y < b.y && a.z < b.z;
}

bool operator< ( const pair<int, coord>& a,
  const pair<int, coord>& b )
{
  return a.first < b.first;
}

int main()
{
  priority_queue<pair<int, coord> > pq;
  set<coord> dup;
  int j = 0;

  for ( int i = 0; i < 10; i++ ) {
    coord save ( j, j + 1, j + 2 );

    if ( dup.find ( save ) == dup.end() ) {
      pq.push ( make_pair ( rand() % 10, save ) );
      dup.insert ( save );
    }

    if ( i % 3 == 0 )
      ++j;
  }

  while ( !pq.empty() ) {
    std::cout<< pq.top().first <<" -- "<< pq.top().second <<'\n';
    pq.pop();
  }
}

Naturally, this can be improved, just like everything I write in a few minutes. ;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.