Solusi saya: kasus terbaik 7,025 bit / angka, kasus terburuk 14,193 bit / angka, rata-rata kasar 8,551 bit / angka. Stream-encoded, tidak ada akses acak.
Bahkan sebelum membaca jawaban ruslik, saya langsung terpikir untuk menyandikan perbedaan antara tiap angka, karena jumlahnya akan kecil dan harus relatif konsisten, tetapi solusinya juga harus dapat mengakomodasi skenario terburuk. Kami memiliki ruang 100000 angka yang hanya berisi 1000 angka. Dalam buku telepon yang sangat seragam, setiap angka akan lebih besar dari angka sebelumnya sebesar 100:
55555-12 3 45
55555-12 4 45
55555-12 5 45
Jika itu masalahnya, itu akan membutuhkan penyimpanan nol untuk menyandikan perbedaan antara angka, karena ini adalah konstanta yang diketahui. Sayangnya, angka mungkin berbeda dari langkah ideal 100. Saya akan menyandikan perbedaan dari kenaikan ideal 100, sehingga jika dua angka yang berdekatan berbeda 103, saya akan menyandikan angka 3 dan jika dua angka yang berdekatan berbeda 92, saya akan menyandikan -8. Saya menyebut delta dari kenaikan ideal 100 sebagai " varians ".
Varians dapat berkisar dari -99 (yaitu dua angka berurutan) hingga 99000 (seluruh buku telepon terdiri dari angka 00000… 00999 dan tambahan nomor terjauh 99999), yang merupakan kisaran 99100 nilai yang memungkinkan.
Saya akan bertujuan untuk mengalokasikan penyimpanan minimal untuk mengkodekan perbedaan yang paling umum dan memperluas penyimpanan jika saya menemukan perbedaan besar (seperti protobuf ‘s varint
). Saya akan menggunakan potongan tujuh bit, enam untuk penyimpanan dan bit bendera tambahan di bagian akhir untuk menunjukkan bahwa varian ini disimpan dengan potongan tambahan setelah yang sekarang, hingga maksimum tiga potongan (yang akan memberikan maksimum 3 * 6 = 18 bit penyimpanan, yang merupakan 262144 nilai yang mungkin, lebih dari jumlah kemungkinan varians (99100). Setiap potongan tambahan yang mengikuti bendera yang ditinggikan memiliki bit dengan signifikansi lebih tinggi, sehingga potongan pertama selalu memiliki bit 0- 5, potongan kedua opsional memiliki bit 6-11, dan potongan ketiga opsional memiliki bit 12-17.
Satu potongan menyediakan enam bit penyimpanan yang dapat menampung 64 nilai. Saya ingin memetakan 64 varian terkecil agar sesuai dalam potongan tunggal itu (yaitu varian -32 hingga +31) jadi saya akan menggunakan pengkodean ProtoBuf ZigZag, hingga varian -99 hingga +98 (karena tidak perlu untuk varian negatif di luar -99), di mana saya akan beralih ke pengkodean biasa, diimbangi dengan 98:
Varians | Nilai Tersandi
----------- + ----------------
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
----------- | --------------- Akhir ZigZag
100 | 198
101 | 199
... | ...
3996 | 4094
3997 | 4095
----------- | --------------- 12 bit
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
----------- | --------------- 18 bit
Beberapa contoh bagaimana varians akan dikodekan sebagai bit, termasuk bendera untuk menunjukkan potongan tambahan:
Varians | Bit yang Dikodekan
----------- + ----------------
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
Jadi, tiga nomor pertama dari buku telepon contoh akan dikodekan sebagai aliran bit sebagai berikut:
BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH # 55555-12345 55555-12448 55555-12491
POS 1 2 3
Skenario kasus terbaik , buku telepon tersebar agak seragam dan tidak ada dua nomor telepon yang memiliki varian lebih besar dari 32, sehingga akan menggunakan 7 bit per nomor ditambah 32 bit untuk nomor awal dengan total 32 + 7 * 999 = 7025 bit .
Skenario campuran , di mana varian nomor telepon 800 cocok dalam satu bagian (800 * 7 = 5600), 180 nomor masuk dalam dua bagian masing-masing (180 * 2 * 7 = 2520) dan 19 nomor cocok dalam tiga bagian masing-masing (20 * 3 * 7 = 399), ditambah 32 bit awal, totalnya 8551 bit .
Skenario kasus terburuk , 25 angka masuk dalam tiga potongan (25 * 3 * 7 = 525 bit) dan 974 angka yang tersisa masuk dalam dua potongan (974 * 2 * 7 = 13636 bit), ditambah 32 bit untuk angka pertama untuk grand jumlah dari14193 bit .
Jumlah nomor yang disandikan |
1 bagian | 2-bagian | 3-bagian | Bit total
--------- + ---------- + ---------- + ------------
999 | 0 | 0 | 7025
800 | 180 | 19 | 8551
0 | 974 | 25 | 14193
Saya dapat melihat empat pengoptimalan tambahan yang dapat dilakukan untuk lebih mengurangi ruang yang diperlukan:
- Potongan ketiga tidak membutuhkan tujuh bit penuh, bisa jadi hanya lima bit dan tanpa bit flag.
- Mungkin ada langkah awal untuk menghitung ukuran terbaik untuk setiap potongan. Mungkin untuk buku telepon tertentu, akan lebih optimal jika potongan pertama memiliki 5 + 1 bit, yang kedua 7 + 1 dan yang ketiga 5 + 1. Itu selanjutnya akan mengurangi ukuran menjadi minimal 6 * 999 + 32 = 6026 bit, ditambah dua set tiga bit untuk menyimpan ukuran potongan 1 dan 2 (ukuran potongan 3 adalah sisa dari 16 bit yang diperlukan) untuk total dari 6032 bit!
- Pass awal yang sama dapat menghitung kenaikan yang diharapkan lebih baik daripada default 100. Mungkin ada buku telepon yang dimulai dari 55555-50000, dan karenanya memiliki setengah rentang angka sehingga kenaikan yang diharapkan harus 50. Atau mungkin ada non-linear distribusi (mungkin deviasi standar) dan beberapa kenaikan harapan optimal lainnya dapat digunakan. Ini akan mengurangi varian tipikal dan memungkinkan potongan pertama yang lebih kecil untuk digunakan.
- Analisis lebih lanjut dapat dilakukan pada langkah pertama untuk memungkinkan buku telepon dipartisi, dengan setiap partisi memiliki peningkatan yang diharapkan dan optimalisasi ukuran potongannya sendiri. Ini akan memungkinkan ukuran potongan pertama yang lebih kecil untuk bagian tertentu dari buku telepon yang sangat seragam (mengurangi jumlah bit yang dikonsumsi) dan ukuran potongan yang lebih besar untuk bagian yang tidak seragam (mengurangi jumlah bit yang terbuang pada tanda kelanjutan).