Каковы некоторые альтернативы немного массива?

StackOverflow https://stackoverflow.com/questions/36106

Вопрос

У меня есть приложение для поиска информации, которое создает битовые массивы по порядку 10 -х миллионов бит. Количество бит «установки» в массиве широко варьируется от всех ясных до всех. В настоящее время я использую прямой массив битов (java.util.BitSet), так что каждый из моих массивов занимает несколько мегабайт.

Мой план - посмотреть на кардинальность первого Не Биты, затем примите решение о том, какую структуру данных использовать для оставшихся. Очевидно, что некоторые структуры данных лучше для очень разреженных битовых массивов, а другие, когда устанавливаются примерно половина битов (когда большинство битов установлено, я могу использовать отрицание для обработки его как разреженного набора нулей).

  • Какие структуры могут быть хороши в каждой крайности?
  • Есть ли посередине?

Вот несколько ограничений или подсказков:

  1. Биты устанавливаются только один раз, а в индексе.
  2. Мне нужна 100% точность, поэтому что -то вроде фильтра «Блум недостаточно».
  3. После того, как набор будет построен, мне нужно иметь возможность эффективно итерации над «набор».
  4. Биты случайным образом распределены, поэтому алгоритмы, кодирующие длину прогона, вряд ли будут намного лучше, чем простой список индексов битов.
  5. Я пытаюсь оптимизировать использование памяти, но скорость все еще несет некоторый масса.

Что -то с реализацией Java с открытым исходным кодом полезно, но не требуется. Меня больше интересует основы.

Это было полезно?

Решение

Если данные не являются действительно случайными и имеет симметричное распределение на 1/0, тогда это просто становится проблемой сжатия данных без потерь и очень аналогична сжатию CCITT Group 3, используемой для черно -белых (то есть бинарных) изображений факсов. CCITT Group 3 использует схему кодирования Хаффмана. В случае факса они используют фиксированный набор кодов Huffman, но для данного набора данных вы можете генерировать определенный набор кодов для каждого набора данных для улучшения достигнутого коэффициента сжатия. Пока вам нужно только получить доступ к битам последовательно, как вы подразумеваете, это будет довольно эффективным подходом. Случайный доступ создаст некоторые дополнительные проблемы, но вы, вероятно, могли бы создать бинарный индекс дерева поиска в различных точках смещения в массиве, которые позволили бы вам приблизиться к желаемому месту, а затем войти оттуда.

Примечание: Схема Huffman по -прежнему работает хорошо, даже если данные являются случайными, если распределение 1/0 не совсем совсем. То есть, чем меньше даже распределение, тем лучше коэффициент сжатия.

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

Другие советы

Я бы решительно рассмотрел использование кодирования диапазона вместо кодирования Хаффмана. В целом, кодирование диапазона может использовать асимметрию более эффективно, чем кодирование Хаффмана, но это особенно так, когда размер алфавита настолько мал. Фактически, когда «нативный алфавит» составляет просто 0 и 1, единственный способ, которым Хаффман может получить любое сжатие, - это объединить эти символы, что именно будет, что будет делать кодирование диапазона более эффективно.

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

Спасибо за ответы. Это то, что я попробую для динамического выбора правильного метода:

Я соберу все первое Не хиты в обычной массиве битов и выберите один из трех методов, основанный на симметрии этого образца.

  • Если образец очень асимметричный, я просто сохраню индексы для установленных битов (или, может быть, расстояние до следующего бита) в списке.
  • Если образец очень симметричный, я буду продолжать использовать обычный битовый массив.
  • Если образец умеренно симметричный, я использую метод сжатия без потерь, такой как Кодирование Хаффмана. Предлагается Inscitekjeff.

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

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

Еще одна мысль о сжатии:

Если массив битов не сумасшедший долго, вы можете попробовать применить Burrows-Wheeler Transform Перед использованием какого -либо кодирования повторения, например, Хаффман. Наивная реализация потребует o (n^2) памяти во время (DE) сжатия и O (n^2 log n) для декомпрессии - также почти наверняка есть ярлыки. Но если в ваших данных вообще есть какая -то последовательная структура, это действительно должно помочь Huffman, кодируя.

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

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

Быстрое комбинаторное доказательство того, что вы не можете сэкономить много места:

Предположим, у вас есть произвольная подмножество N/2 битов, установленных на 1 из N общего количества битов. У вас есть (n n/2) возможности. С использованием Формула Стерлинга, это примерно 2^n / sqrt (n) * sqrt (2 / pi). Если каждая возможность в равной степени вероятно, то нет никакого способа дать более вероятный выбор более коротких представлений. Таким образом, нам нужны биты log_2 (n n/2), которые примерно n - (1/2) log (n) биты.

Это не очень хорошая экономия памяти. Например, если вы работаете с n = 2^20 (1 мег), вы можете сохранить только 10 бит. Это просто не стоит.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top