Giải pháp của tôi: trường hợp tốt nhất 7,025 bit / số, trường hợp xấu nhất 14,193 bit / số, trung bình thô 8,551 bit / số. Được mã hóa luồng, không có quyền truy cập ngẫu nhiên.
Ngay cả trước khi đọc câu trả lời của ruslik, tôi đã nghĩ ngay đến việc mã hóa sự khác biệt giữa mỗi số, vì nó sẽ nhỏ và phải tương đối nhất quán, nhưng giải pháp cũng phải có khả năng ứng phó với trường hợp xấu nhất. Chúng ta có một không gian 100000 số chỉ chứa 1000 số. Trong một danh bạ điện thoại hoàn toàn đồng nhất, mỗi số sẽ lớn hơn số trước đó 100:
55555-12 3 45
55555-12 4 45
55555-12 5 45
Nếu đúng như vậy, nó sẽ yêu cầu bộ nhớ không để mã hóa sự khác biệt giữa các số, vì đó là một hằng số đã biết. Thật không may, các số có thể thay đổi so với các bước lý tưởng là 100. Tôi sẽ mã hóa sự khác biệt so với bước tăng lý tưởng là 100, để nếu hai số liền kề khác nhau 103, tôi sẽ mã hóa số 3 và nếu hai số liền kề khác nhau 92, tôi sẽ mã hóa -8. Tôi gọi delta từ mức tăng lý tưởng 100 là " phương sai ".
Phương sai có thể nằm trong khoảng từ -99 (tức là hai số liên tiếp) đến 99000 (toàn bộ danh bạ bao gồm các số 00000… 00999 và thêm một số xa nhất 99999), là một phạm vi 99100 giá trị có thể có.
Tôi muốn nhắm đến phân bổ một lưu trữ tối thiểu để mã hóa những khác biệt phổ biến nhất và mở rộng lưu trữ nếu tôi gặp phải sự khác biệt lớn hơn (như Protobuf ‘s varint
). Tôi sẽ sử dụng các phần bảy bit, sáu để lưu trữ và một bit cờ bổ sung ở cuối để chỉ ra rằng phương sai này được lưu trữ với một phần bổ sung sau phần hiện tại, tối đa là ba phần (sẽ cung cấp tối đa 3 * 6 = 18 bit dung lượng lưu trữ, là 262144 giá trị có thể có, nhiều hơn số phương sai có thể có (99100). Mỗi đoạn bổ sung theo sau cờ tăng có các bit có ý nghĩa cao hơn, do đó, đoạn đầu tiên luôn có các bit 0- 5, phần thứ hai tùy chọn có các bit 6-11 và phần thứ ba tùy chọn có các bit 12-17.
Một đoạn duy nhất cung cấp sáu bit lưu trữ có thể chứa 64 giá trị. Tôi muốn ánh xạ 64 phương sai nhỏ nhất để vừa với một đoạn duy nhất đó (tức là phương sai từ -32 đến +31) vì vậy, tôi sẽ sử dụng mã hóa ProtoBuf ZigZag, lên đến các phương sai từ -99 đến +98 (vì không cần đối với phương sai âm vượt quá -99), lúc đó tôi sẽ chuyển sang mã hóa thông thường, bù bằng 98:
Phương sai | Giá trị được mã hóa
----------- + ----------------
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
----------- | --------------- Hết ZigZag
100 | 198
101 | 199
... | ...
3996 | 4094
3997 | 4095
----------- | --------------- 12 bit
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
----------- | --------------- 18 bit
Một số ví dụ về cách các phương sai sẽ được mã hóa dưới dạng bit, bao gồm cờ để chỉ ra một đoạn bổ sung:
Phương sai | Các bit được mã hóa
----------- + ----------------
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
Vì vậy, ba số đầu tiên của một danh bạ điện thoại mẫu sẽ được mã hóa thành một dòng bit như sau:
BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH # 55555-12345 55555-12448 55555-12491
POS 1 2 3
Trường hợp tốt nhất , danh bạ điện thoại được phân phối hơi đồng đều và không có hai số điện thoại nào có phương sai lớn hơn 32, vì vậy nó sẽ sử dụng 7 bit cho mỗi số cộng với 32 bit cho số bắt đầu với tổng số 32 + 7 * 999 = 7025 bit .
Một kịch bản hỗn hợp , trong đó phương sai của 800 số điện thoại nằm trong một đoạn (800 * 7 = 5600), 180 số phù hợp với hai đoạn mỗi đoạn (180 * 2 * 7 = 2520) và 19 số vừa với ba đoạn mỗi đoạn (20 * 3 * 7 = 399), cộng với 32 bit ban đầu, tổng cộng là 8551 bit .
Trường hợp xấu nhất , 25 số vừa với ba khối (25 * 3 * 7 = 525 bit) và 974 số còn lại vừa với hai khối (974 * 2 * 7 = 13636 bit), cộng với 32 bit cho số đầu tiên cho một đại Tổng cộng14193 bit .
Lượng số được mã hóa |
1-chunk | 2 khối | 3 khúc | Tổng số bit
--------- + ---------- + ---------- + ------------
999 | 0 | 0 | 7025
800 | 180 | 19 | 8551
0 | 974 | 25 | 14193
Tôi có thể thấy bốn tối ưu hóa bổ sung có thể được thực hiện để giảm thêm dung lượng cần thiết:
- Đoạn thứ ba không cần đầy đủ bảy bit, nó có thể chỉ là năm bit và không cần một bit cờ.
- Có thể có một số lần vượt qua ban đầu để tính toán kích thước tốt nhất cho mỗi đoạn. Có thể đối với một danh bạ nhất định, sẽ là tối ưu nếu đoạn đầu tiên có 5 + 1 bit, 7 + 1 thứ hai và 5 + 1 thứ ba. Điều đó sẽ tiếp tục giảm kích thước xuống tối thiểu 6 * 999 + 32 = 6026 bit, cộng với hai bộ ba bit để lưu trữ kích thước của khối 1 và 2 (kích thước của chunk 3 là phần còn lại của 16 bit được yêu cầu) cho tổng cộng của 6032 bit!
- Cùng một lần vượt qua ban đầu có thể tính toán mức tăng dự kiến tốt hơn so với mặc định 100. Có thể có một danh bạ điện thoại bắt đầu từ 55555-50000 và do đó, danh bạ có một nửa dải số nên mức tăng dự kiến phải là 50. Hoặc có thể có một danh bạ phi tuyến tính có thể sử dụng phân phối (độ lệch chuẩn) và một số gia số dự kiến tối ưu khác. Điều này sẽ làm giảm phương sai điển hình và có thể cho phép sử dụng đoạn đầu tiên thậm chí còn nhỏ hơn.
- Phân tích sâu hơn có thể được thực hiện trong lần vượt qua đầu tiên để cho phép phân vùng danh bạ điện thoại, với mỗi phân vùng có gia số dự kiến và tối ưu hóa kích thước chunk riêng. Điều này sẽ cho phép kích thước đoạn đầu tiên nhỏ hơn cho một số phần nhất định có tính đồng nhất cao của danh bạ điện thoại (giảm số lượng bit được tiêu thụ) và kích thước khối lớn hơn cho các phần không đồng nhất (giảm số lượng bit bị lãng phí trên cờ tiếp tục).