2016-04-13 3 views
2

У меня есть большой список ключей многокомпонентных построен из типов поите данные с операторами сравнения определенно:Быстрого частичное соответствие с ключами многокомпонентными

typedef boost::tuple<int, char, unsigned long> Key; 

Этих ключами я хочу, чтобы соответствовать против фиксированных шаблонов набора, который состоит из тех же компонентов, но, в частности рисунка некоторые компоненты могут быть опущены:

typedef boost::tuple< 
    boost::optional<int> 
    , boost::optional<char> 
    , boost::optional<unsigned long> > Pattern; 

подталкивание :: опционально со значением отключенном представляет звездочку, «Соответствуют всем»:

Key(1, 2, 3) match Pattern(1, 2, *) 
Key(1, 2, 3) match Pattern(*, 2, 3) 

И я хочу, чтобы выполнить матчи быстрее, чем O (N), где N является количество моделей.

Я начал с пользовательского оператора сравнения1 для узоров , чтобы сохранить их в отсортированном виде. Оператор1 просто сортирует звездочки после всего остального. Затем выполните запросы с помощью std :: lower_bound с пользовательским оператором сравнения2. Оператор2 отключает блокировку ключевых компонентов во время сравнения. Но я не могу уйти с разовым сортированным вектором , потому что если второй компонент - это *, и я его пропустил , то нет гарантии, что «срез» третьих компонентов отсортирован , и я получаю что-то полезное с помощью std :: lower_bound.

+1

вам понадобится один указатель на «форму» поиска. построение индексов дорого, но вы можете использовать unordered_map, чтобы получить среднее постоянное время поиска. –

ответ

2

Отсортировать ключи в определенном порядке. Создайте индекс для каждого компонента, поддерживая тот же порядок сортировки.

Найдите следующий элемент для каждого компонента, используя индекс. Если индексы указывают на тот же элемент, у вас есть совпадение. Если не выбрать компонент, указывающий на наименьший элемент (в порядке сортировки) и пропустить, пока вы не достигнете наибольшего значения (std :: lower_bound сделает это).

Это тот же алгоритм для пересечения отсортированных списков.

Скорость зависит от того, насколько плотны ваши данные. Если вы ищете (*, *, true) и 95% совпадений с данными, вы будете O (N). Если данные достаточно разрежены, это может быть очень быстрым.

+0

Рекомендуется использовать несколько ключей для каждого из ваших индексов и попытаться организовать их так, чтобы набор * всех префиксов * этих упорядоченных списков ключей покрывал как можно больше (неупорядоченных) наборов ключей. Например. предположим, что есть 4 поля: A, B, C и D, тогда вы можете сделать 4 индекса: ABCD, BCD, CDA, DBA. Теперь на любой запрос, который указывает все 4 или любые 3 из 4 полей, может быть дан ответ с помощью одного бинарного поиска, и единственными видами запросов, для которых требуется объединение типа, который вы описываете, являются те, которые указывают только AC или только AD. (Конечно, вы могли бы добавить еще 2 индекса для этого.) –

+0

Я сопоставляю один ключ против набора шаблонов за раз. Скажем, у меня есть K (1,2,3) и [P (1,2,4), P (1,2, *)]. Какой составной индекс я должен использовать? Как сказал Сорин, я должен сделать индекс для каждого компонента, запросить каждый индекс как для значения компонента, так и для * и пересечь результирующие (шесть) списков. –

+0

@DmitryTeslenko Да, у вас есть правильная идея. – Sorin

Смежные вопросы