Я хочу расширить ответ @AProgrammer.
Ваша хеш-карта проста, потому что она настраивается в соответствии с вашими потребностями. С другой стороны, std::tr1::unordered_map
должен выполнить ряд различных задач, и преуспеть во всех случаях. Это требует подхода средней производительности во всех случаях, поэтому он никогда не будет превосходным в любой конкретной области.
Хэш-контейнеры очень специфичны тем, что есть много способов их реализации, вы выбрали Open-Addressing, в то время как стандарт навязывает подходы для разработчиков. Оба имеют разные компромиссы, и это одна из причин, по которой стандарт на этот раз фактически обеспечил реализацию конкретной реализации: чтобы производительность не сильно изменилась при переключении с одной библиотеки на другую. Простого указания сложности / амортизации Big-O здесь было бы недостаточно.
Вы говорите, что указали unordered_map
относительно количества элементов финала, но изменили ли вы коэффициент загрузки? Цепочка, как известно, «плохая» (из-за нехватки памяти) в случае коллизий, и использование меньшего коэффициента загрузки будет способствовать распространению ваших элементов.
В заключение отметим одно отличие: что происходит, когда вы изменяете размер своей хэш-карты? Используя цепочку, unordered_map
не перемещает элементы в памяти:
- ссылки на них все еще действительны (даже если итераторы могут быть недействительными)
- в случае больших или сложных объектов вызов конструкторов копирования не производится
Это в отличие от вашей простой реализации , которая может принести O(N)
копий (если вы не используете линейную перефразировку для распространения работы, но это определенно не просто).
Следовательно, кажется, что для unordered_map
было выбрано сглаживание шипов за счет более медленной средней вставки.
Есть кое-что, что вы можете сделать, хотя бы: предоставить пользовательский распределитель . Записав определенный распределитель для вашего сценария использования, и выделите всю его память за один раз (поскольку вы знаете, сколько объектов будет вставлено, и можете иметь распределитель, сообщающий, сколько памяти является узлом). Затем выделите узлы в виде стека (простое увеличение указателя). Это должно улучшить (несколько) производительность.