Мое решение: лучший случай 7,025 бит / число, наихудший случай 14,193 бит / число, грубое среднее 8,551 бит / число. Потоковое кодирование без произвольного доступа.
Еще до прочтения ответа Руслика я сразу подумал о кодировании разницы между каждым числом, поскольку оно будет небольшим и должно быть относительно непротиворечивым, но решение также должно быть в состоянии приспособиться к наихудшему сценарию. У нас есть пространство 100000 номеров, которые содержат только 1000 номеров. В абсолютно однородной телефонной книге каждый номер будет больше, чем предыдущий номер на 100:
55555-12 3 45
* 1008 55555-12 * 4 45
55555-12 5 45
Если бы это было так, для кодирования различий между числами потребовалось бы нулевое хранение, поскольку это известная константа. К сожалению, числа могут отличаться от идеальных шагов 100. Я бы закодировал разницу от идеального приращения 100, так что если два соседних числа отличаются на 103, я бы закодировал число 3, а если два соседних числа отличаются на 92, я закодировал бы -8. Я называю дельту с идеальным приращением 100 « дисперсия ».
Дисперсия может варьироваться от -99 (т.е. два последовательных номера) до 99000 (вся телефонная книга состоит из номеров 00000… 00999 и дополнительного дальнего номера 99999), что составляет диапазон 99100 возможных значений.
Я бы хотел выделить минимальное хранилище для кодирования наиболее распространенных различий и расширить хранилище, если я столкнусь с большими различиями (например, ProtoBuf 's varint
). Я буду использовать куски из семи битов, шесть для хранения и дополнительный бит флага в конце, чтобы указать, что эта дисперсия сохраняется с дополнительным фрагментом после текущего, максимум до трех блоков (что обеспечит максимум 3 * 6 = 18 бит памяти, что на 262144 возможных значения больше, чем число возможных отклонений (99100). Каждый дополнительный блок, следующий за поднятым флагом, имеет биты более высокой значимости, поэтому первый блок всегда имеет биты 0- 5, необязательные вторые порции имеют биты 6-11, а необязательные третьи порции имеют биты 12-17.
Один блок обеспечивает шесть битов памяти, которые могут вместить 64 значения. Я хотел бы отобразить 64 наименьших отклонения, чтобы они поместились в этот отдельный блок (то есть отклонения от -32 до +31), поэтому я буду использовать кодирование ProtoBuf ZigZag, вплоть до отклонений от -99 до +98 (поскольку в этом нет необходимости для отрицательной дисперсии за пределами -99), после чего я переключусь на обычное кодирование, смещение на 98:
Variance | Encoded Value
-----------+----------------
0 | 0
-1 | 1
1 | 2
-2 | 3
2 | 4
-3 | 5
3 | 6
... | ...
-31 | 61
31 | 62
-32 | 63
-----------|--------------- 6 bits
32 | 64
-33 | 65
33 | 66
... | ...
-98 | 195
98 | 196
-99 | 197
-----------|--------------- End of ZigZag
100 | 198
101 | 199
... | ...
3996 | 4094
3997 | 4095
-----------|--------------- 12 bits
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
-----------|--------------- 18 bits
1031 *
Некоторые примеры того, как дисперсии будут кодироваться как биты, включая флаг для указания дополнительного фрагмента:
Variance | Encoded Bits
-----------+----------------
0 | 000000 0
5 | 001010 0
-8 | 001111 0
-32 | 111111 0
32 | 000000 1 000001 0
-99 | 000101 1 000011 0
177 | 010011 1 000100 0
14444 | 001110 1 100011 1 000011 0
Таким образом, первые три числа в примере телефонной книги будут закодированы в виде потока битов следующим образом:
BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH# 55555-12345 55555-12448 55555-12491
POS 1 2 3
В лучшем случае , телефонная книга распределена несколько равномерно, и нет двух телефонных номеров с дисперсией больше 32, поэтому для начального номера будет использоваться 7 бит на номер плюс 32 бита всего 32 + 7 * 999 = 7025 бит .
Смешанный сценарий , где дисперсия 800 телефонных номеров вписывается в один блок (800 * 7 = 5600), 180 номеров помещаются в два блока каждый (180 * 2 * 7 = 2520), а 19 номеров - в три каждый кусок (20 * 3 * 7 = 399), плюс начальные 32 бита, итого 8551 бит .
Сценарий наихудшего случая , 25 чисел помещаются в три блока (25 * 3 * 7 = 525 бит), а остальные 974 числа помещаются в два блока (974 * 2 * 7 = 13636 бит), плюс 32 бита для первое число для общей суммы 14193 бит .
Amount of encoded numbers |
1-chunk | 2-chunks | 3-chunks | Total bits
---------+----------+----------+------------
999 | 0 | 0 | 7025
800 | 180 | 19 | 8551
0 | 974 | 25 | 14193
Я вижу четыре дополнительные оптимизации, которые можно выполнить для дальнейшего уменьшения необходимого пространства:
- Третий блок не нуждается в полных семи битах, он может быть только пятью битами и без флага.
- Может быть начальныйПередача чисел для расчета лучших размеров для каждого куска.Возможно, для определенной телефонной книги было бы оптимальным, чтобы первый блок имел 5 + 1 бит, второй 7 + 1 и третий 5 + 1.Это дополнительно уменьшило бы размер до минимума 6 * 999 + 32 = 6026 битов, плюс два набора по три бита для хранения размеров фрагментов 1 и 2 (размер фрагмента 3 - это остаток от необходимых 16 битов) для общего количестваиз 6032 битов!
- Один и тот же начальный проход может вычислить лучшее ожидаемое приращение, чем значение по умолчанию 100. Возможно, есть телефонная книга, которая начинается с 55555-50000, и поэтому имеет половину диапазона номеров, поэтому ожидаемое приращение должнобыть 50. Или, возможно, существует нелинейное распределение (возможно, стандартное отклонение), и может быть использовано другое оптимальное ожидаемое приращение.Это уменьшит типичную дисперсию и может позволить использовать еще меньший первый блок.
- На первом проходе можно провести дополнительный анализ, чтобы разрешить разбиение телефонной книги, причем каждый раздел имеет свой ожидаемый прирост.и оптимизация размера куска.Это позволило бы уменьшить размер первого чанка для некоторых весьма однородных частей телефонной книги (уменьшить количество потребляемых битов) и увеличить размеры чанков для неоднородных частей (уменьшить количество битов, теряемых на флагах продолжения).