Mi solución: el mejor de los casos 7.025 bits / número, el peor de los casos 14.193 bits / número, promedio aproximado de 8.551 bits / número. Stream-codificado, sin acceso aleatorio.
Incluso antes de leer la respuesta de ruslik, inmediatamente pensé en codificar la diferencia entre cada número, ya que será pequeño y debería ser relativamente consistente, pero la solución también debe poder adaptarse al peor de los casos. Tenemos un espacio de 100000 números que contienen solo 1000 números. En una guía telefónica perfectamente uniforme, cada número sería mayor que el número anterior en 100:
55555-12 3 45
55555-12 4 45
55555-12 5 45
Si ese fuera el caso, requeriría almacenamiento cero para codificar las diferencias entre números, ya que es una constante conocida. Desafortunadamente, los números pueden variar de los pasos ideales de 100. Codificaría la diferencia del incremento ideal de 100, de modo que si dos números adyacentes difieren en 103, codificaría el número 3 y si dos números adyacentes difieren en 92, I codificaría -8. Yo llamo al delta de un incremento ideal de 100 la " varianza ".
La variación puede variar de -99 (es decir, dos números consecutivos) a 99000 (toda la agenda telefónica consta de los números 00000 ... 00999 y un número adicional más lejano 99999), que es un rango de 99100 valores posibles.
Me intentar asignar un almacenamiento mínimo para codificar las diferencias más comunes y ampliar el almacenamiento, si me encuentro con diferencias más grandes (como protobuf ‘s varint
). Usaré fragmentos de siete bits, seis para almacenamiento y un bit de bandera adicional al final para indicar que esta variación se almacena con un fragmento adicional después del actual, hasta un máximo de tres fragmentos (que proporcionarán un máximo de 3 * 6 = 18 bits de almacenamiento, que son 262144 valores posibles, más que el número de posibles variaciones (99100). Cada fragmento adicional que sigue a una bandera elevada tiene bits de mayor importancia, por lo que el primer fragmento siempre tiene bits 0- 5, el segundo fragmento opcional tiene los bits 6-11, y el tercer fragmento opcional tiene los bits 12-17.
Un solo fragmento proporciona seis bits de almacenamiento que pueden albergar 64 valores. Me gustaría mapear las 64 variaciones más pequeñas para que quepan en ese único fragmento (es decir, variaciones de -32 a +31), así que usaré la codificación ProtoBuf ZigZag, hasta las variaciones de -99 a +98 (ya que no es necesario para una variación negativa más allá de -99), momento en el que cambiaré a la codificación normal, compensada por 98:
Varianza | 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 | sesenta y cinco
33 | 66
... | ...
-98 | 195
98 | 196
-99 | 197
----------- | --------------- Fin de ZigZag
100 | 198
101 | 199
... | ...
3996 | 4094
3997 | 4095
----------- | --------------- 12 bits
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
----------- | --------------- 18 bits
Algunos ejemplos de cómo las variaciones se codificarían como bits, incluida la bandera para indicar un fragmento adicional:
Varianza | 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
Por lo tanto, los primeros tres números de una guía telefónica de muestra se codificarían como un flujo de bits de la siguiente manera:
BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH # 55555-12345 55555-12448 55555-12491
POS 1 2 3
En el mejor de los casos , la guía telefónica está distribuida de manera algo uniforme y no hay dos números de teléfono que tengan una variación mayor que 32, por lo que usaría 7 bits por número más 32 bits para el número inicial para un total de 32 + 7 * 999 = 7025 bits .
Un escenario mixto , donde la varianza de 800 números de teléfono se ajusta a una parte (800 * 7 = 5600), 180 números caben en dos partes cada uno (180 * 2 * 7 = 2520) y 19 números caben en tres partes cada uno (20 * 3 * 7 = 399), más los 32 bits iniciales, suman 8551 bits .
En el peor de los casos , 25 números caben en tres partes (25 * 3 * 7 = 525 bits) y los 974 números restantes caben en dos partes (974 * 2 * 7 = 13636 bits), más 32 bits para el primer número de un gran Total de14193 bits .
Cantidad de números codificados |
1 trozo | 2 trozos | 3 trozos | Bits totales
--------- + ---------- + ---------- + ------------
999 | 0 | 0 | 7025
800 | 180 | 19 | 8551
0 | 974 | 25 | 14193
Puedo ver cuatro optimizaciones adicionales que se pueden realizar para reducir aún más el espacio requerido:
- El tercer fragmento no necesita los siete bits completos, puede ser solo de cinco bits y sin un bit de bandera.
- Puede haber un pase inicial de los números para calcular los mejores tamaños para cada fragmento. Tal vez para un directorio telefónico determinado, sería óptimo tener el primer fragmento con 5 + 1 bits, el segundo 7 + 1 y el tercero 5 + 1. Eso reduciría aún más el tamaño a un mínimo de 6 * 999 + 32 = 6026 bits, más dos conjuntos de tres bits para almacenar los tamaños de los fragmentos 1 y 2 (el tamaño del fragmento 3 es el resto de los 16 bits requeridos) para un total de 6032 bits!
- El mismo paso inicial puede calcular un incremento esperado mejor que el valor predeterminado 100. Tal vez haya una guía telefónica que comience en 55555-50000, por lo que tenga la mitad del rango de números, por lo que el incremento esperado debería ser 50. O tal vez haya una guía no lineal Se puede utilizar la distribución (desviación estándar tal vez) y algún otro incremento esperado óptimo. Esto reduciría la variación típica y podría permitir el uso de un primer fragmento aún más pequeño.
- Se pueden realizar más análisis en la primera pasada para permitir la partición de la guía telefónica, con cada partición con su propio incremento esperado y optimizaciones de tamaño de fragmento. Esto permitiría un tamaño de primer fragmento más pequeño para ciertas partes altamente uniformes de la guía telefónica (reduciendo el número de bits consumidos) y tamaños de fragmentos más grandes para partes no uniformes (reduciendo el número de bits desperdiciados en indicadores de continuación).