Ma solution: meilleur des cas 7,025 bits / nombre, pire des cas 14,193 bits / nombre, moyenne approximative de 8,551 bits / nombre. Encodé en flux, pas d'accès aléatoire.
Avant même de lire la réponse de ruslik, j'ai tout de suite pensé à encoder la différence entre chaque nombre, car elle sera petite et devrait être relativement cohérente, mais la solution doit aussi pouvoir s'adapter au pire des cas. Nous avons un espace de 100 000 nombres qui ne contiennent que 1 000 nombres. Dans un annuaire téléphonique parfaitement uniforme, chaque numéro serait supérieur de 100 au numéro précédent:
55555-12 3 45
55555-12 4 45
55555-12 5 45
Si tel était le cas, il faudrait un stockage nul pour encoder les différences entre les nombres, car il s'agit d'une constante connue. Malheureusement, les nombres peuvent différer des étapes idéales de 100. Je coderais la différence par rapport à l'incrément idéal de 100, de sorte que si deux nombres adjacents diffèrent de 103, j'encoderais le nombre 3 et si deux nombres adjacents diffèrent de 92, je encoderait -8. J'appelle le delta d'un incrément idéal de 100 la « variance ».
La variance peut aller de -99 (c'est-à-dire deux numéros consécutifs) à 99000 (le répertoire entier comprend les numéros 00000… 00999 et un numéro supplémentaire le plus éloigné 99999), ce qui correspond à une plage de 99100 valeurs possibles.
Je viserais à allouer un stockage minimal pour encoder les différences les plus courantes et étendre le stockage si je rencontre des différences plus importantes (comme celles de ProtoBufvarint
). J'utiliserai des morceaux de sept bits, six pour le stockage et un bit d'indicateur supplémentaire à la fin pour indiquer que cette variance est stockée avec un morceau supplémentaire après l'actuel, jusqu'à un maximum de trois morceaux (ce qui fournira un maximum de 3 * 6 = 18 bits de stockage, soit 262144 valeurs possibles, soit plus que le nombre de variances possibles (99100). Chaque bloc supplémentaire qui suit un drapeau levé a des bits de plus grande signification, donc le premier bloc a toujours les bits 0- 5, les seconds morceaux facultatifs ont les bits 6-11 et le troisième bloc facultatif a les bits 12-17.
Un seul bloc fournit six bits de stockage pouvant accueillir 64 valeurs. Je voudrais mapper les 64 plus petites variances pour qu'elles tiennent dans ce seul bloc (c'est-à-dire des variances de -32 à +31), donc j'utiliserai l'encodage ProtoBuf ZigZag, jusqu'aux variances de -99 à +98 (car il n'y a pas besoin pour une variance négative au-delà de -99), à quel point je passerai à l'encodage normal, décalé de 98:
Variance | Valeur codée
----------- + ----------------
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
----------- | --------------- Fin du zigzag
100 | 198
101 | 199
... | ...
3996 | 4094
3997 | 4095
----------- | --------------- 12 bits
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
----------- | --------------- 18 bits
Quelques exemples de la façon dont les variances seraient codées sous forme de bits, y compris le drapeau pour indiquer un bloc supplémentaire:
Variance | Bits codés
----------- + ----------------
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
Ainsi, les trois premiers numéros d'un exemple d'annuaire téléphonique seraient codés comme un flux de bits comme suit:
BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH # 55555-12345 55555-12448 55555-12491
POS 1 2 3
Dans le meilleur des cas , l'annuaire téléphonique est distribué de manière quelque peu uniforme et il n'y a pas deux numéros de téléphone qui ont une variance supérieure à 32, donc il utiliserait 7 bits par numéro plus 32 bits pour le numéro de départ pour un total de 32 + 7 * 999 = 7025 bits .
Un scénario mixte , où la variance de 800 numéros de téléphone s'inscrit dans un bloc (800 * 7 = 5600), 180 numéros entrent dans deux morceaux chacun (180 * 2 * 7 = 2520) et 19 nombres entrent dans trois morceaux chacun (20 * 3 * 7 = 399), plus les 32 bits initiaux, totalisent 8551 bits .
Dans le pire des cas , 25 nombres tiennent en trois morceaux (25 * 3 * 7 = 525 bits) et les 974 nombres restants entrent en deux morceaux (974 * 2 * 7 = 13636 bits), plus 32 bits pour le premier nombre d'un grand total de14193 bits .
Quantité de nombres encodés |
1-morceau | 2 morceaux | 3 morceaux | Nombre total de bits
--------- + ---------- + ---------- + ------------
999 | 0 | 0 | 7025
800 | 180 | 19 | 8551
0 | 974 | 25 | 14193
Je peux voir quatre optimisations supplémentaires qui peuvent être effectuées pour réduire davantage l'espace requis:
- Le troisième morceau n'a pas besoin des sept bits complets, il peut s'agir de seulement cinq bits et sans bit de drapeau.
- Il peut y avoir une première passe des nombres pour calculer les meilleures tailles pour chaque morceau. Peut-être que pour un certain répertoire, il serait optimal que le premier bloc ait 5 + 1 bits, le deuxième 7 + 1 et le troisième 5 + 1. Cela réduirait encore la taille à un minimum de 6 * 999 + 32 = 6026 bits, plus deux ensembles de trois bits pour stocker les tailles des blocs 1 et 2 (la taille du bloc 3 est le reste des 16 bits requis) pour un total de 6032 bits!
- La même passe initiale peut calculer un meilleur incrément attendu que la valeur par défaut 100. Peut-être y a-t-il un annuaire téléphonique qui commence de 55555-50000, et donc il a la moitié de la plage de numéros, donc l'incrément attendu devrait être de 50. Ou peut-être qu'il y a un répertoire non linéaire distribution (écart-type peut-être) et un autre incrément optimal attendu peut être utilisé. Cela réduirait la variance typique et pourrait permettre d'utiliser un premier bloc encore plus petit.
- Une analyse plus approfondie peut être effectuée lors de la première passe pour permettre le partitionnement de l'annuaire téléphonique, chaque partition ayant ses propres optimisations d'incrément et de taille de bloc attendues. Cela permettrait une taille de premier bloc plus petite pour certaines parties très uniformes de l'annuaire téléphonique (réduisant le nombre de bits consommés) et des tailles de blocs plus grandes pour les parties non uniformes (réduisant le nombre de bits gaspillés sur les indicateurs de continuation).