Вопрос

I would like to count the number of entries between two iterators of an std::multimap in less than O(N) time. Are there any tricks or clever ways to do this?

Since std::multimap has bidirectional iterators, my understanding is that something like std::distance could do this in O(N) time.

Additional details: The multimap's key is an N-tuple. I'm trying to find the number of entries in the multimap whose key's first element is 0. The options for the first element of they key are 0 and 1, and the multimap uses a strict weak ordering in which the first element of the key is always the most important. i.e., all elements with 0 come before any elements with 1.

Context: The iterators are returned by equal_range, which runs in logarithmic time. Declaratively, I'd like to measure the length of the range.

Thank you.

Это было полезно?

Решение

What you are looking for is so-called heterogeneous comparison lookup that was proposed in N3465. It allows for a different but compatible comparison function in the equal_range member function that is being used to store the Key. In your case, the lookup comparison operator (first tuple member) would be different from but consistent with the tuple lexicographical comparison.

Unfortunately, only a small portion of that paper has been accepted into the draft C++14 Standard, according to this Q&A. However, the N3465 paper's author is also the author of Boost.MultiIndex that has implemented this feature. You can emulate a std::multimap by following the Boost.MultiIndex documentation.

Once you have used the generalized equal_range member function of an adapted boost::multiindex_container, you can then simply do std::distance() on the returned iterators. Complexity would be logarithmic in the container size for the equal_range and linear in the size of the returned iterator range. If you are not interested in the result but only in the count, there is also a generalized count() member function returning that in the same logarithmic + linear time.

Другие советы

You want to use the std::distance method from the Iterator library. The reference is at std::distance. Here is the main reference: Iterator library.

The description reads thus as of March 25, 2014:

template< class InputIt >
typename std::iterator_traits<InputIt>::difference_type
    distance( InputIt first, InputIt last );

Returns the number of elements between first and last.

The behavior is undefined if last is not reachable from first by (possibly repeatedly) incrementing first.

Parameters
first - iterator pointing to the first element
last - iterator pointing to the last element

Type requirements
- InputIt must meet the requirements of InputIterator. The operation is more efficient if InputIt additionally meets the requirements of RandomAccessIterator

Return value
The number of elements between first and last.

Complexity
Linear.
However, if InputIt additionally meets the requirements of RandomAccessIterator, complexity is constant.


Note that the above details are subject to change. The most accurate information will be obtained by navigating to the std::distance reference page directly.

Sample code from the std::distance reference web page:

include <iostream>
#include <iterator>
#include <vector>

int main() 
{
    std::vector<int> v{ 3, 1, 4 };

    auto distance = std::distance(v.begin(), v.end());

    std::cout << distance << '\n';
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top