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'; }