Быстрый контейнер для установки битов в разреженной области и итерации (C ++)? - PullRequest
5 голосов
/ 22 ноября 2008

Мне нужен быстрый контейнер только с двумя операциями. Вставка ключей из очень разреженной области (все 32-битные целые числа и приблизительно 100 задаются в данный момент времени) и итерация по вставленным ключам. Он должен иметь дело с множеством вставок, которые попадают в одни и те же записи (например, 500k, но только в 100 разных).

В настоящее время я использую std :: set (только insert и итеративный интерфейс), который неплох, но все еще недостаточно быстр. std :: unordered_set был в два раза медленнее, то же самое для Google Hash Maps. Интересно, какая структура данных оптимизирована для этого случая?

Ответы [ 9 ]

6 голосов
/ 22 ноября 2008

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

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

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

3 голосов
/ 22 ноября 2008

Я не уверен, что понимаю «много вставок, которые попадают в одни и те же записи». Вы имеете в виду, что есть только 100 значений, которые когда-либо были членами, но 500k в основном дублирующих операций, которые вставляют одно из этих 100 значений?

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

Я оставляю создание хэша в качестве упражнения для читателя, поскольку, как я знаю, оно существует как техника, но я никогда сам не изучал ее. Суть в том, чтобы получить быстрый хеш в максимально возможном диапазоне, чтобы для каждого n, m в ваших 100 значениях хэш (n)! = Хэш (m).

Таким образом, вставка выглядит как array[hash(value)] = 1;, удаление выглядит как array[hash(value)] = 0; (хотя вам это не нужно), и для перечисления вы запускаете массив, и для каждого установленного значения в индексе n, inverse_hash (n) равен в вашей коллекции. Для небольшого диапазона вы можете легко поддерживать справочную таблицу для выполнения обратного хэша или вместо сканирования всего массива в поисках установленных флагов, вы можете запустить 100 возможных значений, проверяя каждое по очереди.

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

1 голос
/ 22 ноября 2008

Рандомизированная структура данных может быть идеальной для вашей работы. Взгляните на список пропусков - хотя я не знаю какой-либо его реализации на C ++. Я намеревался отправить его в Boost, но так и не удосужился это сделать.

1 голос
/ 22 ноября 2008

Возможно, вы захотите реализовать HashTree , используя базовую 10-хеш-функцию на каждом уровне вместо бинарной хеш-функции. Вы можете либо сделать его не сгруппированным, в этом случае ваша производительность будет детерминированной (log10), либо скорректировать размер корзины на основе ожидаемого распределения, чтобы у вас была только пара ключей / корзина.

1 голос
/ 22 ноября 2008

Для используемого набора, который должен быть таким маленьким, хеш-таблица без упаковки может быть в порядке. Если вы можете жить со случайной операцией расширения, увеличьте ее в степени 2, если она заполнена более чем на 70%. Хеширование кукушки было обсуждено на Stackoverflow до и также может быть хорошим подходом для такого маленького набора. Если вам действительно нужно оптимизировать скорость, вы можете реализовать функцию хеширования и поиск в ассемблере - в линейных структурах данных это будет очень просто, поэтому работа по кодированию и обслуживанию для реализации на ассемблере не должна быть слишком сложной для поддержки. *

0 голосов
/ 22 ноября 2008

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

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

0 голосов
/ 22 ноября 2008

Сколько у вас памяти? 32-разрядные файлы занимают «только» 4 ГБ / 8 байт, что составляет 512 МБ, что не так много для высокопроизводительного сервера. Это сделало бы ваши вставки O (1). Но это может замедлить итерацию. Хотя пропуск всех слов только с нулями оптимизирует большинство итераций. Если ваши 100 номеров находятся в относительно небольшом диапазоне, вы можете оптимизировать их еще больше, сохраняя минимальное и максимальное значения.

Я знаю, что это просто грубая сила, но иногда грубой силы достаточно хорошо.

0 голосов
/ 22 ноября 2008

Обратите внимание, что, хотя вставка в хеш-таблицу выполняется быстро, ее итерация не особенно быстрая, поскольку вам нужно выполнять итерацию по всему массиву.

Какая операция у вас медленная? Вы делаете больше вставок или больше итераций?

0 голосов
/ 22 ноября 2008

Может быть набор с b-деревом (вместо двоичного дерева) в качестве внутренней структуры данных. Я нашел эту статью о codeproject, которая реализует это.

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