У меня есть две разные реализации одной и той же функции
IPAddress UMNS::lookup(const HostName& name) const{
auto it=ns.find(name);
if(it!=ns.end()){
return (*it).second;
}
return NON_EXISTING_ADDRESS;
}
а также
IPAddress UMNS::lookup(const HostName& name) const{
auto it=find_if(ns.begin(),ns.end(),
[&name] ( const pair<HostName,IPAddress> &a){ return a.first==name;});
bool found = it != ns.end();
if ( found ){
return (*it).second;
}
return NON_EXISTING_ADDRESS;
}
ns является unordered_map
но время выполнения двух функций не одинаково.
Первая реализация дает следующее:
Кол-во запросов: 1000000
Среднее время поиска (мс): 0,000373
Вторая реализация дает следующее:
Кол-во запросов: 1000000
Среднее время поиска (мс): 24,9
Что случилось со второй реализацией?
Почему я не могу использовать find_if?
find_if
ничего не знает о том, является ли find_if
им последовательность контейнером, не говоря уже о том, предлагает ли этот контейнер оптимизированный способ выполнения одной и той же задачи. Он будет перебирать последовательность, которую он дал, применяя предикат, данный ему, который (для большого контейнера) будет намного медленнее, чем поиск на основе хэшей, предоставляемый функцией собственного find
контейнера.
find_if
все еще будет перебирать карту и применять ее предикат; он до сих пор ничего не знает о контейнерах. map::find
(возможно) будет несколько медленнее, чем unordered_map::find
так как он выполняет поиск в логарифмическом времени, а не поиск по хешу.
std::find_if
предназначен для работы с любыми Итераторами ввода, которые могут поступать из других контейнеров, таких как std::vector
. Чтобы найти элемент в общих контейнерах, подобных этому, ему необходимо выполнить линейный поиск по всем элементам, пока не найдет тот, который он ищет. С другой стороны, элемент find
std::unordered_map
разработан специально для этого контейнера и способен находить элементы в среднем постоянном времени.
find_if
- это наименее универсальная версия, которая не использует внутреннюю структуру контейнера или порядок. Таким образом, он использует обычный поиск O (n). С членом find
вы получаете O(1)
поиск, так как unordered_map
реализован в виде хэш - таблицы.
find_if
должен просматривать каждую запись на карте, пока не найдет ту, которую вы ищете, потому что она не знает, что вторая реализация эквивалентна первой, потому что она не может видеть внутри предиката, который вы ему даете (и компилятор не может его оптимизировать).
find_if
, вероятно, не учат работать сunordered_map
и поэтому просто использует линейный поиск по сравнению с поиском по хешу O (1). Также вопрос качества, тьфу. :-D