Minha solução: melhor caso 7,025 bits / número, pior caso 14,193 bits / número, média aproximada de 8,551 bits / número. Codificado em fluxo, sem acesso aleatório.
Antes mesmo de ler a resposta de ruslik, pensei imediatamente em codificar a diferença entre cada número, pois será pequeno e deve ser relativamente consistente, mas a solução também deve ser capaz de acomodar o pior cenário. Temos um espaço de 100.000 números que contêm apenas 1.000 números. Em uma lista telefônica perfeitamente uniforme, cada número seria maior do que o número anterior em 100:
55555-12 3 45
55555-12 4 45
55555-12 5 45
Se fosse esse o caso, seria necessário armazenamento zero para codificar as diferenças entre os números, uma vez que é uma constante conhecida. Infelizmente, os números podem variar dos passos ideais de 100. Eu codificaria a diferença do incremento ideal de 100, de modo que se dois números adjacentes diferirem por 103, eu codificaria o número 3 e se dois números adjacentes diferirem por 92, I codificaria -8. Eu chamo o delta de um incremento ideal de 100 de “ variância ”.
A variação pode variar de -99 (ou seja, dois números consecutivos) a 99000 (toda a lista telefônica consiste em números 00000… 00999 e um número mais distante adicional 99999), que é uma faixa de 99100 valores possíveis.
Eu pretendem alocar um mínimo de armazenamento para codificar as diferenças mais comuns e expandir o armazenamento se eu encontrar diferenças maiores (como Protobuf ‘s varint
). Usarei pedaços de sete bits, seis para armazenamento e um bit de sinalizador adicional no final para indicar que essa variação é armazenada com um pedaço adicional após o atual, até um máximo de três pedaços (o que fornecerá um máximo de 3 * 6 = 18 bits de armazenamento, que são 262144 valores possíveis, mais do que o número de variações possíveis (99100). Cada pedaço adicional que segue um sinalizador elevado tem bits de significância mais alta, então o primeiro pedaço sempre tem bits 0- 5, os segundos pedaços opcionais têm os bits 6-11 e o terceiro pedaço opcional tem os bits 12-17.
Um único bloco fornece seis bits de armazenamento que podem acomodar 64 valores. Eu gostaria de mapear as 64 menores variações para caber naquele único pedaço (ou seja, variações de -32 a +31), então usarei a codificação ProtoBuf ZigZag, até as variações de -99 a +98 (já que não há necessidade para uma variação negativa além de -99), ponto em que mudarei para a codificação regular, com deslocamento de 98:
Variância | Valor Codificado
----------- + ----------------
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
----------- | --------------- Fim do ZigZag
100 198
101 199
... | ...
3996 | 4094
3997 | 4095
----------- | --------------- 12 bits
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
----------- | --------------- 18 bits
Alguns exemplos de como as variações seriam codificadas como bits, incluindo o sinalizador para indicar um fragmento adicional:
Variância | Bits codificados
----------- + ----------------
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
Portanto, os três primeiros números de uma amostra de catálogo telefônico seriam codificados como um fluxo de bits da seguinte forma:
BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH # 55555-12345 55555-12448 55555-12491
POS 1 2 3
Na melhor das hipóteses , a lista telefônica é distribuída de maneira um tanto uniforme e não há dois números de telefone com variação maior do que 32, então ele usaria 7 bits por número mais 32 bits para o número inicial para um total de 32 + 7 * 999 = 7025 bits .
Um cenário misto , em que a variação de 800 números de telefone se encaixa em um bloco (800 * 7 = 5600), 180 números se encaixam em dois blocos cada (180 * 2 * 7 = 2520) e 19 números se encaixam em três blocos cada (20 * 3 * 7 = 399), mais os 32 bits iniciais, totalizam 8.551 bits .
Na pior das hipóteses , 25 números cabem em três blocos (25 * 3 * 7 = 525 bits) e os 974 números restantes cabem em dois blocos (974 * 2 * 7 = 13636 bits), mais 32 bits para o primeiro número de um grande total de14193 bits .
Quantidade de números codificados |
1 pedaço | 2 pedaços | 3 pedaços | Bits totais
--------- + ---------- + ---------- + ------------
999 | 0 | 0 | 7025
800 | 180 19 8551
0 | 974 | 25 14193
Posso ver quatro otimizações adicionais que podem ser realizadas para reduzir ainda mais o espaço necessário:
- O terceiro pedaço não precisa dos sete bits completos, pode ter apenas cinco bits e sem um bit de sinalizador.
- Pode haver uma passagem inicial dos números para calcular os melhores tamanhos para cada pedaço. Talvez para uma determinada lista telefônica, seria ótimo ter o primeiro bloco com 5 + 1 bits, o segundo 7 + 1 e o terceiro 5 + 1. Isso reduziria ainda mais o tamanho para um mínimo de 6 * 999 + 32 = 6026 bits, mais dois conjuntos de três bits para armazenar os tamanhos dos blocos 1 e 2 (o tamanho do bloco 3 é o restante dos 16 bits necessários) para um total de 6032 bits!
- A mesma passagem inicial pode calcular um incremento esperado melhor do que o padrão 100. Talvez haja uma lista telefônica que começa em 55555-50000 e, portanto, tem metade do intervalo de números, então o incremento esperado deve ser 50. Ou talvez haja um catálogo não linear distribuição (desvio padrão talvez) e algum outro incremento ideal esperado pode ser usado. Isso reduziria a variação típica e poderia permitir que um primeiro pedaço ainda menor fosse usado.
- Uma análise posterior pode ser feita na primeira passagem para permitir que a lista telefônica seja particionada, com cada partição tendo seu próprio incremento esperado e otimizações de tamanho de bloco. Isso permitiria um primeiro tamanho de bloco menor para certas partes altamente uniformes da lista telefônica (reduzindo o número de bits consumidos) e tamanhos de bloco maiores para partes não uniformes (reduzindo o número de bits desperdiçados em sinalizadores de continuação).