La mia soluzione: caso migliore 7.025 bit / numero, caso peggiore 14.193 bit / numero, media approssimativa 8.551 bit / numero. Codifica in streaming, nessun accesso casuale.
Anche prima di leggere la risposta di ruslik, ho subito pensato di codificare la differenza tra ogni numero, poiché sarà piccolo e dovrebbe essere relativamente coerente, ma la soluzione deve anche essere in grado di accogliere lo scenario peggiore. Abbiamo uno spazio di 100000 numeri che contengono solo 1000 numeri. In una rubrica telefonica perfettamente uniforme, ogni numero sarebbe maggiore di 100 rispetto al numero precedente:
55555-12 3 45
55555-12 4 45
55555-12 5 45
Se fosse così, richiederebbe zero memoria per codificare le differenze tra i numeri, poiché è una costante nota. Sfortunatamente, i numeri possono variare dai passi ideali di 100. Codificherei la differenza dall'incremento ideale di 100, in modo che se due numeri adiacenti differiscono di 103, codificherei il numero 3 e se due numeri adiacenti differiscono di 92, io codificherebbe -8. Chiamo il delta da un incremento ideale di 100 la " varianza ".
La varianza può variare da -99 (cioè due numeri consecutivi) a 99000 (l'intera rubrica è composta dai numeri 00000… 00999 e da un numero più lontano aggiuntivo 99999), che è un intervallo di 99100 valori possibili.
Mi piacerebbe lo scopo di assegnare un minimo di stoccaggio per codificare le differenze più comuni ed espandere la memoria, se io incontro differenze più grandi (come protobuf s’ varint
). Userò blocchi di sette bit, sei per l'archiviazione e un bit flag aggiuntivo alla fine per indicare che questa varianza è memorizzata con un blocco aggiuntivo dopo quello corrente, fino a un massimo di tre blocchi (che fornirà un massimo di 3 * 6 = 18 bit di memoria, che sono 262144 valore possibile, più del numero di varianze possibili (99100). Ogni blocco aggiuntivo che segue un flag rialzato ha bit di importanza maggiore, quindi il primo blocco ha sempre bit 0- 5, il secondo blocco opzionale ha bit 6-11 e il terzo blocco opzionale ha bit 12-17.
Un singolo blocco fornisce sei bit di archiviazione che possono contenere 64 valori. Vorrei mappare le 64 varianze più piccole per adattarle a quel singolo blocco (cioè varianze da -32 a +31) quindi userò la codifica ProtoBuf ZigZag, fino alle varianze da -99 a +98 (poiché non è necessario per una varianza negativa oltre -99), a quel punto passerò alla codifica normale, offset di 98:
Varianza | Valore codificato
----------- + ----------------
0 | 0
-1 | 1
1 | 2
-2 | 3
2 | 4
-3 | 5
3 | 6
... | ...
-31 | 61
31 | 62
-32 | 63
----------- | --------------- 6 bit
32 | 64
-33 | 65
33 | 66
... | ...
-98 | 195
98 | 196
-99 | 197
----------- | --------------- Fine di ZigZag
100 | 198
101 | 199
... | ...
3996 | 4094
3997 | 4095
----------- | --------------- 12 bit
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
----------- | --------------- 18 bit
Alcuni esempi di come le varianze verrebbero codificate come bit, incluso il flag per indicare un blocco aggiuntivo:
Varianza | Bit codificati
----------- + ----------------
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
Quindi i primi tre numeri di un esempio di rubrica telefonica sarebbero codificati come un flusso di bit come segue:
BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH # 55555-12345 55555-12448 55555-12491
POS 1 2 3
Nella migliore delle ipotesi , la rubrica è distribuita in modo un po 'uniforme e non ci sono due numeri di telefono con una varianza maggiore di 32, quindi userebbe 7 bit per numero più 32 bit per il numero iniziale per un totale di 32 + 7 * 999 = 7025 bit .
Uno scenario misto , in cui la varianza di 800 numeri di telefono rientra in un blocco (800 * 7 = 5600), 180 numeri si adattano a due blocchi ciascuno (180 * 2 * 7 = 2520) e 19 numeri si adattano a tre blocchi ciascuno (20 * 3 * 7 = 399), più i 32 bit iniziali, per un totale di 8551 bit .
Nel peggiore dei casi , 25 numeri si adattano a tre blocchi (25 * 3 * 7 = 525 bit) e i rimanenti 974 numeri si adattano a due blocchi (974 * 2 * 7 = 13636 bit), più 32 bit per il primo numero per un grande totale di14193 bit .
Quantità di numeri codificati |
1 pezzo | 2 pezzi | 3 pezzi | Bit totali
--------- + ---------- + ---------- + ------------
999 | 0 | 0 | 7025
800 | 180 | 19 | 8551
0 | 974 | 25 | 14193
Vedo quattro ulteriori ottimizzazioni che possono essere eseguite per ridurre ulteriormente lo spazio richiesto:
- Il terzo blocco non ha bisogno dei sette bit completi, può essere solo di cinque bit e senza un bit flag.
- Può esserci un passaggio iniziale dei numeri per calcolare le dimensioni migliori per ogni blocco. Forse per una certa rubrica, sarebbe ottimale avere il primo blocco con 5 + 1 bit, il secondo 7 + 1 e il terzo 5 + 1. Ciò ridurrebbe ulteriormente la dimensione a un minimo di 6 * 999 + 32 = 6026 bit, più due serie di tre bit per memorizzare le dimensioni dei blocchi 1 e 2 (la dimensione del blocco 3 è il resto dei 16 bit richiesti) per un totale di 6032 bit!
- Lo stesso passaggio iniziale può calcolare un incremento previsto migliore rispetto al valore predefinito 100. Forse c'è una rubrica telefonica che inizia da 55555-50000 e quindi ha metà dell'intervallo numerico, quindi l'incremento previsto dovrebbe essere 50. O forse c'è un non lineare la distribuzione (forse la deviazione standard) e qualche altro incremento atteso ottimale può essere utilizzato. Ciò ridurrebbe la varianza tipica e potrebbe consentire l'utilizzo di un primo blocco ancora più piccolo.
- Ulteriori analisi possono essere eseguite nel primo passaggio per consentire il partizionamento della rubrica, con ogni partizione con il proprio incremento previsto e ottimizzazioni della dimensione del blocco. Ciò consentirebbe una dimensione del primo blocco più piccola per alcune parti altamente uniformi della rubrica telefonica (riducendo il numero di bit consumati) e dimensioni di blocchi più grandi per parti non uniformi (riducendo il numero di bit sprecati in flag di continuazione).