Структура данных для эффективного возврата записей top-K хеш-таблицы (карта, словарь) - PullRequest
6 голосов
/ 21 января 2010

Вот описание:

Он работает как обычная карта с методами get, put и remove, но имеет метод getTopKEntries(int k) для получения элементов top-K, отсортированных по ключу:

Для моего конкретного случая использования я добавляю, удаляю и корректирую множество значений в структуре, но в любой момент времени существует приблизительно 500-1000 элементов; Я хочу эффективно вернуть записи для 10 лучших ключей.

  • Я вызываю put и remove методы много раз.
  • Я вызываю метод getTopKEntries.
  • Я вызываю методы put и remove еще несколько раз.
  • Я вызываю метод getTopKEntries.
  • ...

Я надеюсь, что операции O (1) get, put и remove и getTopKEntries будут зависеть только от K, а не от размера карты.

Так что же такое структура данных для эффективного возврата элементов top-K карты?

Мой другой вопрос аналогичен, но для случая возврата всех элементов карты, отсортированных по ключу.

Если это помогает, ключи и значения являются 4-байтовыми целыми числами.

Ответы [ 8 ]

2 голосов
/ 21 января 2010

Бинарное дерево поиска (т. Е. std::map в C ++) звучит как идеальная структура: оно уже лексикографически упорядочено, то есть простой обход в порядке приведет к элементам в порядке возрастания. Следовательно, итерация по первым k элементам приведет непосредственно к верхним k элементам.

Кроме того, поскольку вы предвидите множество операций «удаления», хеш-таблица в любом случае не подойдет: операции удаления разрушают характеристики коэффициента загрузки хеш-таблиц, что приводит к быстрому ухудшению времени выполнения. *

1 голос
/ 21 января 2010

Альтернативой может быть просто сортировка предметов.

В вашем сценарии использования есть только 1000 элементов - их сортировка выполняется просто невероятно быстро (имейте в виду, что log 2 1000 ≈ 10 = почти 1), и, похоже, она тоже не выполняется часто.

Вы можете даже адаптировать алгоритм выбора , чтобы вернуть K наименьших элементов. К сожалению, это все еще зависит от n , а не только от k , как вы и ожидали: O ( n + k log k ).

(я добавил это как новый ответ, потому что он фактически совершенно не связан с моей первой записью.)

1 голос
/ 21 января 2010

Я не уверен, что полностью согласен с мнением Конрада о том, что большое количество операций удаления разрушит структуру хеш-таблицы.

Без операций удаления вы можете сохранить все объекты в хеш-таблице и сохранить верхнюю букву K в куче приоритетов, которая будет постепенно обновляться. Это сделало бы вставку O (1 + log K), то есть постоянное время в N, предполагая, что K является постоянным и не зависит от N (N = количество объектов в таблице). Однако это не работает, если у вас есть операция удалить . Предложенная куча Фибоначчи имеет амортизированную операцию удаления O (log N), поэтому она также не дает хорошего решения, поскольку все объекты необходимо будет хранить в куче, и если вы в конечном итоге удалите каждый вставленный объект, вы получите O (log N) поведение в целом для пары вставка + удаление.

Возможно, я бы попробовал следующий подход:

Храните объекты в хеш-таблице, предполагая, что вам нужна вся таблица для каких-то других целей, кроме возврата верхних объектов. Поддерживайте приоритетную кучу (стандартная куча), которая содержит объекты K * C для C, значение которого необходимо искать экспериментально. Всякий раз, когда вы добавляете новый объект, попробуйте вставить его в кучу; если он помещается в пространство K C (куча еще не заполнена, или он отталкивает другой объект), вставьте его и установите бит в хеш-таблицу, чтобы указать, что объект находится в куче; когда вы выталкиваете объект из кучи, очищайте бит. Когда вы удалите объект, проверьте бит; если бит = 1, т. е. объект находился в куче, удалите его оттуда (его нужно искать, если у вас нет указателя на него из хеш-таблицы; лучше сохранить указатель). Что происходит сейчас, так это то, что куча уменьшается. Ключевым моментом является то, что , пока в куче еще как минимум K объектов , в нем гарантированно содержатся все верхние K объектов. Вот где появляется фактор С, поскольку он обеспечивает «запас» для кучи. Когда размер кучи опускается ниже K, вы запускаете линейное сканирование всей хеш-таблицы и заполняете кучу обратно до емкости K C.

Установка C является эмпирической, потому что она зависит от того, как ваши объекты приходят и уходят; но его настройка должна быть простой, поскольку вы можете настроить его только на основе профилирования во время выполнения.

Сложность: вставка O (1 + log (KC)). Remove - это O (1 + p log (KC) + q N), где p - вероятность того, что удаленный объект был в куче, а q - вероятность того, что куча должна быть восстановлена. р зависит от характеристик того, как объекты приходят и уходят. Для простого анализа мы можем установить p = (KC / N), то есть принять равномерную вероятность. q еще более чувствителен к «потоку» объектов. Например, если новые объекты в целом со временем увеличивают свою стоимость и вы всегда удаляете более старые объекты, q стремится к нулю.

Обратите внимание, что, как ни странно, p равно обратно пропорционально пропорционально N, так что на самом деле эта часть ускоряется при увеличении N:)

0 голосов
/ 26 января 2010

Мне кажется, куча - лучшая структура данных для этой проблемы. Потому что, положить, удалить и вернуть K верхних элементов можно вернуть за O (klog (N)) время. Используйте max-heap, если вы хотите max элементов.

Здесь я предполагаю, что k верхних элементов означает, что вам нужно k элементов, имеющих максимальное значение.

0 голосов
/ 21 января 2010

Если ключ сортировки представляет собой простое целое или десятичное число, то поиск будет довольно быстрым. Он будет использовать память, и технически найти элемент в дереве - O (log n). Но на практике это будет что-то вроде log 256 n, поэтому постоянный коэффициент очень маленький (log 256 из 2 миллиардов = 4).

0 голосов
/ 21 января 2010

Если я сегодня не слишком креативен, вы просто не можете делать все это за O (1).

Если вы поддерживаете порядок сортировки, то добавления и удаления, вероятно, будут в O (log n). Если нет, то ваш поиск должен быть O (n).

Хеш-таблицы просто не выполняют сортировку. Я предлагаю вам жить с O (log n) для вставок и удалений и использовать одну из предложенных структур данных (вероятно, лучше всего использовать Heap). Если вам нужен O (1) поиск, вы можете объединить хеш, но тогда вы поддерживаете две структуры данных параллельно и можете использовать TreeMap.

0 голосов
/ 21 января 2010

Возможно, вы захотите кучу (хотя удаление может быть проблемой).

0 голосов
/ 21 января 2010

Я бы порекомендовал куча Фибоначчи .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...