Учитывая то, что вы сказали, я бы очень серьезно подумал об использовании std::vector<pair<int, float> >
и использовании std::lower_bound
, std::upper_bound
и / или std::equal_range
для поиска значений.
В то время как точные служебные данные std::map
могут (и могут) изменяться, практически нет места для вопроса о том, что он обычно потребляет дополнительную память и ищут значения более медленно чем бинарный поиск в векторе. Как вы заметили, это обычно (и почти неизбежно) реализуется как некое сбалансированное дерево, которое накладывает накладные расходы на указатели и информацию о балансировке и, как правило, означает, что каждый узел также выделяется отдельно. Поскольку ваши узлы довольно малы (обычно 8 байт), дополнительные данные, вероятно, будут как минимум такими же, как те, что вы на самом деле храните (т. Е. Как минимум 100% накладных расходов). Отдельное распределение часто означает плохую локальность ссылок, что приводит к плохому использованию кэша.
В большинстве реализаций std::map
используется красно-черное дерево. Если вы собираетесь использовать std::map
, реализация, использующая дерево AVL, вероятно, подойдет вам лучше - дерево AVL имеет несколько более жесткие ограничения на балансировку. Это дает немного более быстрый поиск за счет немного более медленного вставки и удаления (так как он должен чаще балансировать, чтобы поддерживать более строгую интерпретацию «сбалансированного»). Пока ваши данные остаются постоянными во время использования, std::vector
почти наверняка лучше.
Еще одна возможность, которую стоит отметить: если ваши ключи хотя бы достаточно даже распределены, вы можете попробовать поискать, используя интерполяцию вместо деления пополам. то есть вместо того, чтобы всегда начинать с середины вектора, вы выполняете линейную интерполяцию, чтобы угадать наиболее вероятную начальную точку поиска. Конечно, если ваши ключи следуют некоторому известному нелинейному распределению, вы можете использовать вместо этого соответствующую интерполяцию.
Предполагая, что ключи достаточно равномерно распределены (или, по крайней мере, следуют некоторому предсказуемому шаблону, который поддается интерполяции), поиск интерполяции имеет сложность O (log log N). Для 130 миллионов ключей это составляет около 4 проб, чтобы найти предмет. Чтобы сделать это значительно лучше, чем при обычном / неидеальном хешировании, вам нужен хороший алгоритм, и вы должны держать коэффициент загрузки в таблице достаточно низким (обычно около 75% или около того), т.е. вам необходимо учитывать что-то вроде 32 миллионов дополнительных (пустых) мест в вашей таблице, чтобы увеличить ожидаемую сложность с четырех проб до трех). Возможно, я просто старомоден, но мне кажется, что много дополнительного хранилища для такого небольшого улучшения скорости.
OTOH, это правда, что это почти идеальная ситуация для идеального хеширования - набор известен заранее, и ключ довольно мал (важно, поскольку хэширование обычно линейно по размеру ключа). Несмотря на это, если ключи не распределены довольно неравномерно, я не ожидаю какого-либо значительного улучшения - идеальная хеш-функция часто (обычно?) Довольно сложна.