0

How can I efficiently search for a value in a multimap with a time complexity of O(log(n))?

I have a multimap where the keys represent locations and the values represent city names. I want to efficiently search for a specific city name in the multimap based on the given city name.

This is the data structure:

 std::multimap < Location, std::string, LessX > _mmapCitiesX; 

Here is the search function that I have implemented (this is working):

City CitiesManager::findCity(const std::string& cityName) const { auto it = std::find_if(_mmapCitiesX.begin(), _mmapCitiesX.end(), [&](const City& city) { return city.second == cityName; }); if (it == _mmapCitiesX.end()) { throw std::runtime_error(cityName + " isn't found in the city list. Please try again"); } return *it; } 

(City is std::pair<Location, std::string>, and Location is a struct with x,y cords)

To reduce complexity , I attempted to use the std::equal_range, but it didn't work...

here is my attemp:

City CitiesManager::findCity(const std::string& cityName) const { auto range = std::equal_range(_mmapCitiesX.begin(), _mmapCitiesX.end(), cityName, [](const City& city, const std::string& name) { return city.second < name; }); if (range.first == range.second) { throw std::runtime_error(cityName + " isn't found in the city list. Please try again"); } return *(range.first); } 

I get error:

C2664 'bool CitiesManager::findCity::<lambda_1>::operator ()(const City &,const std::basic_string<char,std::char_traits,std::allocator> &) const': cannot convert argument 1 from 'const _Ty' to 'const City &'

edit: This is LessX, I need it because I want to sort the locations by x-chords, and therefore I choose to use Location as key.

struct LessX { bool operator()(const Location& left, const Location& right) const { return left._x < right._x; } }; 

I would appreciate any help

10
  • 3
    You can't. Only the keys in a a map can be searched in O(ln N). Your choice of data structure is not suitable for the requirement. If you need to search the city names, then you'll need e.g. a map where the city names are keys. Commented May 17, 2023 at 8:53
  • you sure? in cppreference they said: "The number of comparisons performed is logarithmic in the distance between first and last" Commented May 17, 2023 at 8:57
  • 3
    std::equal_range requires the range to be (partially) ordered with respect to the provided predicate, but the (multi)map range is ordered according to its keys. So you generally violate the precondition of the function if you use it to search map values. Commented May 17, 2023 at 9:00
  • @DanielG equal_range cannot perform magic. If your data structure is not ordered by city name then log(N) complexity is not achievable. Commented May 17, 2023 at 9:09
  • 4
    Boost MultiIndex might be what you are looking for Commented May 17, 2023 at 9:14

1 Answer 1

3

You can't. Even if you fix your call site, you are ignoring the preconditions of std::equal_range, so your program is ill-formed.

If you want to lookup by both location and name, you need a data structure that provides such a lookup. boost::bimap or boost::multi_index are containers that can provide that.

Sign up to request clarification or add additional context in comments.

2 Comments

wow thanks, and I can still keep it ordered by keys?
Yes. bimap orders by both the left and right value, and multi_index orders by however many things you want

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.