tags:

views:

92

answers:

2

Is there a nice and simple way to find nth element in C++ std::map? Particularly I'm looking for an algorithm to erase the last k elements from the map. That would make sense to retrieve the iterator to the nth element and call std::map::erase. The requirement is that complexity doesn't suffer - that should be possible to erase the element range in O(N).

Copy of the data shouldn't be made just to erase the elements. For example one solution is to copy the data into std::vector, then do std::nth_element on std::vector, and then std::map::find to find the iterator in order to find out where to erase from.

One of other solutions is to just iterate over std::map maintaining a counter variable on the number of elements to remove. That would give O(n). Is that possible to replace the for loop with STL algorithm?

A: 

Edit: Answer not applicable after edit of original post.

Gunner
That is exactly what I would not like to do.
Leonid
+7  A: 

Maps don't provide better-than-linear access to elements by index, like vector or deque. You can do this using std::advance, but it takes time that is proportional to k. If k is small, it will often be fast enough - it basically involves following k pointers. Here's an example:

template<typename Map>
void erase_last_elements(Map & map, ptrdiff_t k)
{
    assert(k >= 0);
    assert(map.size() >= (size_t)k);
    typename Map::iterator i = map.end();
    std::advance(i, -k);
    map.erase(i, map.end());
}

Alternatively, if you're using Boost, you can use boost::prior:

template<typename Map>
void erase_last_elements(Map & map, ptrdiff_t k)
{
    assert(k >= 0);
    assert(map.size() >= (size_t)k);
    typename Map::iterator i = boost::prior(map.end(), k);
    map.erase(i, map.end());
}

Otherwise, you'll have to maintain a separate index, or use a different container. Something like a sorted vector might be appropriate, if you don't insert and remove elements too much.

Doug
Is there any reason why `std::map` doesn't provide a `O(log(n))` solution to access the nth element?
Leonid
It should be more efficient to remove "end() - 1" for k times.
Stefan Majewsky
That sounds like a reasonable solution Stefan.
Leonid
@Leonid - they don't have fast access to the Nth element because they'd have to maintain a separate index, which would require more memory, or slow down inserting or deleting.
Doug
@Stefan - why do you think it would be faster to do that? Asymptotically, the complexity is the same, and there are potentially fewer tree rebalances required if you remove them all in one erase call.
Doug
@Doug - right, that makes sense. You can get away with 4 bytes per node in a tree, but mostly it would be redundant, especially when elements are similar in size to integers in a map.
Leonid