эффективное извлечение элементов из неупорядоченного набора C ++ - PullRequest
0 голосов
/ 18 июня 2020

В C ++ предположим, что у вас есть неупорядоченный набор (https://en.cppreference.com/w/cpp/container/unordered_set) строк - есть ли способ эффективно извлечь все строки из этого набора, которые соответствуют определенным критериям (например, найти все строки в наборе начинающиеся с буквы «а») с использованием метода, отличного от перебора всего набора с a для l oop и проверки первого символа каждой строки?

Ответы [ 3 ]

2 голосов
/ 18 июня 2020

Для любых критериев это невозможно, см. этот ответ для получения более подробной информации.

В зависимости от ваших других потребностей, отсортировано std::vector - это весьма вероятно, что будет наиболее эффективным только для экстракционной части. Используйте алгоритмы вроде std::lower_bound для работы с sorted std::vector. В конце концов, ваши фактические варианты использования - это то, что в целом определяет, какой контейнер лучше всего подходит с точки зрения производительности - хотя std::vector близок к универсальному подходу для всех, учитывая производительность (это из-за всего внутреннего Оптимизация непрерывного хранилища).

При этом, как правило, рекомендуется использовать контейнер, который кажется наиболее подходящим для решения данной проблемы, и делать умные оптимизации только в том случае, если есть реальное узкое место в производительности.

2 голосов
/ 18 июня 2020

Для общего случая любых критериев вы не можете сделать лучше, чем перебирать каждый элемент.

Каждый контейнер имеет специфические c критерии , с которыми он может работать лучше, например,

std::set<std::string> strings = /* something */;
auto first = strings.lower_bound("a"); // O(log(strings)), "a" is the least string that starts with 'a'
auto last = strings.lower_bound("b"); // O(log(strings)), "b" is the first string after those that start with 'a'
strings.erase(first, last); // O(log(strings) + distance(first, last)), all the strings starting with 'a' are removed

Здесь мы удаляем элементы, начинающиеся с 'a', со сложностью of O(log(strings) + distance(first, last)), что является улучшением O(alphabet) по сравнению с повторением всех элементов.

Или более надуманным

std::unordered_set<std::string> strings = /* something */;
auto hashed = strings.hash_function()("Any collision will do"); // O(1)
strings.erase(strings.begin(hashed), strings.end(hashed)); // O(distance(first, last))

Здесь мы удаляем элементы, которые имеют sh такие же, как "Any collision will do" , сложностью O(distance(first, last))

0 голосов
/ 18 июня 2020

Вместо использования неупорядоченного набора адаптируйте структуру данных к чему-то вроде tr ie. В этом случае он может быть более полезным для вас.

Для получения дополнительной информации проверьте: https://en.wikipedia.org/wiki/Trie

Реализация: https://www.geeksforgeeks.org/trie-insert-and-search/.

В зависимости от ваших потребностей вы можете подумать о некоторых других алгоритмах, таких как Aho-Corasick / Suffix-Arrays et c. Возможно, вам придется провести некоторое исследование структуры данных, которая вам нужна, в зависимости от объема имеющихся данных, необходимого вам пересчета и количества выполняемых вами запросов. 1015 *

...