более быстрое сравнение строк для сортировки, для уникального()

У меня есть 4e7 std::strings, каждая длиной от 3 до 30 символов, со многими дубликатами. Я помещаю их в std::set.

Вызов set::insert для каждой строки становится невыносимо медленным задолго до того, как он завершится примерно с 1e7 уникальными строками. Поэтому вместо этого я push_back разбиваю каждую строку на vector, sort() и unique(), а затем переместите строки в set.

Он по-прежнему медленный, но, по крайней мере, он завершает: 4 секунды для накопления вектора, еще 30 для sort(), еще 3 для unique().

Узким местом является sort(). Но мне не нужно, чтобы строки были лексикографически отсортированы! Мне просто нужно, чтобы повторяющиеся строки были непрерывными, для unique(). Их порядок не имеет значения. Есть ли более простая и быстрая функция сравнения строк для sort(), которую я мог бы использовать вместо функции по умолчанию?

Или я должен построить набор быстрее, перебирая вектор с хеш-таблицей сбоку, чтобы пропустить дубликаты? Или заменить set на hash_set или unordered_set?

Редактировать: я собираю Linux с помощью g++ 4.8.4 с единственными флагами -std=c++11 -O3.


person Camille Goudeseune    schedule 08.08.2019    source источник
comment
Я определенно рекомендую вам измерять с помощью std::unordered_set.   -  person Some programmer dude    schedule 08.08.2019
comment
Актуально, возможно дубликат: stackoverflow.com/q/14023106/1896169   -  person Justin    schedule 08.08.2019
comment
В этом сообщении в блоге (?) есть обсуждение запрошенного алгоритма: lemire.me/blog/2008/05/01/   -  person Justin    schedule 08.08.2019
comment
@CamilleGoudeseune Я не вижу упоминания о том, как вы создали свое приложение, которое тестируете. Вы используете оптимизированную сборку или отладочную неоптимизированную сборку?   -  person PaulMcKenzie    schedule 08.08.2019
comment
Идея, предполагающая сравнение строк, является частью проблемы: вы можете предварительно вычислить хэши строк и отсортировать их на основе этого хеша. В каждой области одинаковых хэшей вам придется сортировать снова из-за возможных коллизий хэшей, но все же возможно, что это может быть быстрее.   -  person Justin    schedule 08.08.2019
comment
Если вам просто нужно сделать строки уникальными, я бы рекомендовал использовать std::unordered_set (из сторонней библиотеки для хэш-наборов, если вам нужна дополнительная производительность. std::unordered_set ограничена в том, насколько производительной она может быть из-за требований ее интерфейса)   -  person Alecto Irene Perez    schedule 08.08.2019
comment
Правильная структура данных — unordered_set, и дублирующаяся ссылка не является идеальным совпадением, но это говорит о том, что у вас также могут возникнуть проблемы с ненужными временными объектами при создании набора. Поскольку std::set имеет ту же сложность, что и сортировка вектора, если это показывает разницу в скорости, то у вас есть проблемы с временными объектами, и они, вероятно, все еще будут присутствовать в решении unordered_set. Но нам сложно там помочь, так как вы не выложили код.   -  person Kenny Ostrom    schedule 08.08.2019
comment
Если вы знаете, что ваши строки никогда не будут длиннее 30 символов, вы можете попробовать заменить std::string, например, на char[32] или что-то подобное. Избегание выделения кучи может обеспечить значительное ускорение.   -  person Jeremy Friesner    schedule 09.08.2019


Ответы (1)


@Someprogrammerdude, @J.AntonioPerez, @KennyOstrom: std::unordered_set в 6 раз быстрее. Отправьте ответ, и я приму его. (Возможно, это предложение потерялось во всех этих комментариях.)

vector<string> v;
loop { v.push_back(my_string[i]; }

Медленный оригинал:

sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
set<string> noduplicates = set<string>(
  make_move_iterator(v.begin()), make_move_iterator(v.end()));

В 6 раз быстрее, чем предыдущий блок кода:

unordered_set<string> noduplicates =
  unordered_set<string>(
  make_move_iterator(v.begin()), make_move_iterator(v.end()));
person Camille Goudeseune    schedule 08.08.2019
comment
Вы можете принять свой собственный ответ. Это все еще правильный ответ, и вы приложили усилия для его проверки. - person Hatted Rooster; 09.08.2019
comment
В 6 раз быстрее, чем sorted_set, или в 6 раз быстрее, чем sort+unique? - person davidbak; 09.08.2019
comment
Чем сортировать+стирать+уникально+перемещать, то есть предыдущий блок кода. - person Camille Goudeseune; 09.08.2019