내 솔루션 : 최상의 경우 7.025 비트 / 숫자, 최악의 경우 14.193 비트 / 숫자, 대략적인 평균 8.551 비트 / 숫자. 스트림 인코딩, 임의 액세스 없음.
ruslik의 답변을 읽기 전에도 각 숫자의 차이를 인코딩하는 것을 즉시 생각했습니다. 작은 숫자이고 상대적으로 일관성이 있어야하기 때문입니다.하지만 솔루션은 최악의 시나리오도 수용 할 수 있어야합니다. 1000 개의 숫자 만 포함 된 100000 개의 숫자 공간이 있습니다. 완벽하게 균일 한 전화 번호부에서 각 번호는 이전 번호보다 100 씩 커집니다.
55555-12 3 45
55555-12 4 45
55555-12 5 45
이 경우 알려진 상수이기 때문에 숫자 간의 차이를 인코딩하기 위해 저장 공간이 필요하지 않습니다. 안타깝게도 숫자는 이상적인 단계 인 100과 다를 수 있습니다. 이상적인 증분 100과의 차이를 인코딩하여 두 개의 인접한 숫자가 103만큼 다르면 숫자 3을 인코딩하고 두 개의 인접한 숫자가 92만큼 다르면 I -8을 인코딩합니다. 이상적인 증분 인 100의 델타를“ 분산 ” 이라고 부릅니다 .
분산의 범위는 -99 (즉, 두 개의 연속 된 숫자)에서 99000 (전체 전화 번호부는 숫자 00000… 00999 및 추가적으로 가장 먼 번호 99999로 구성됨) 범위이며 99100 개의 가능한 값 범위입니다.
나는 (같은 더 큰 차이가 발생하면 가장 일반적인 차이를 인코딩 및 스토리지를 확장 할 수있는 최소한의 스토리지를 할당하는 것을 목표 것 ProtoBuf 의 varint
). 저는 7 비트 청크, 저장을 위해 6 개, 마지막에 추가 플래그 비트를 사용하여이 분산이 현재 청크 이후에 추가 청크와 함께 최대 3 개의 청크 (최대 3 * 6 = 가능한 분산 수 (99100)보다 많은 262144 개의 가능한 값인 18 비트 저장 공간. 올린 플래그 뒤에 오는 각 추가 청크에는 더 높은 의미의 비트가 있으므로 첫 번째 청크에는 항상 비트 0- 도 5에서, 선택적 두 번째 청크에는 비트 6-11이 있고 선택적 세 번째 청크에는 비트 12-17이 있습니다.
단일 청크는 64 개의 값을 수용 할 수있는 6 비트 스토리지를 제공합니다. 단일 청크 (즉, -32에서 +31의 분산)에 맞게 64 개의 가장 작은 분산을 매핑하고 싶습니다. 따라서 ProtoBuf ZigZag 인코딩을 사용하여 최대 -99에서 +98까지 분산 할 것입니다 (필요가 없기 때문에 -99를 초과하는 음의 편차),이 시점에서 98만큼 오프셋 된 일반 인코딩으로 전환합니다.
차이 | 인코딩 된 값
----------- + ----------------
0 | 0
-1 | 1
1 | 2
-2 | 삼
2 | 4
-3 | 5
3 | 6
... | ...
-31 | 61
31 | 62
-32 | 63
----------- | --------------- 6 비트
32 | 64
-33 | 65
33 | 66
... | ...
-98 | 195
98 | 196
-99 | 197
----------- | --------------- ZigZag 끝
100 | 198
101 | 199
... | ...
3996 | 4094
3997 | 4095
----------- | --------------- 12 비트
3998 | 4096
3999 | 4097
... | ...
262045 | 262143
----------- | --------------- 18 비트
추가 청크를 나타내는 플래그를 포함하여 분산이 비트로 인코딩되는 방법에 대한 몇 가지 예 :
차이 | 인코딩 된 비트
----------- + ----------------
0 | 000000 0
5 | 001010 0
-8 | 001111 0
-32 | 111111 0
32 | 000000 1 000001 0
-99 | 000101 1 0000110
177 | 010011 1 000100 0
14444 | 001110 1 100011 1 0000110
따라서 샘플 전화 번호부의 처음 세 숫자는 다음과 같이 비트 스트림으로 인코딩됩니다.
BIN 000101001011001000100110010000011001 000110 1 010110 1 000010
PH # 55555-12345 55555-12448 55555-12491
POS 1 2 3
가장 좋은 시나리오 는 전화 번호부가 다소 균일하게 분포되어 있고 분산이 32보다 큰 두 개의 전화 번호가 없기 때문에 번호 당 7 비트에 시작 번호로 32 비트를 사용하여 총 32 + 7 * 999가됩니다. = 7025 비트 . 800 개의 전화 번호 차이가 하나의 청크 (800 * 7 = 5600)에 들어가고 180 개의 번호가 각각 두 개의 청크 (180 * 2 * 7 = 2520)에 들어가고 19 개의 번호가 각각 3 개의 청크에 들어가는
혼합 시나리오 (20 * 3 * 7 = 399)이고 초기 32 비트를 더하면 총 8551 비트가 됩니다.
최악의 경우 25 개의 숫자는 3 개의 청크 (25 * 3 * 7 = 525 비트)에 적합하고 나머지 974 개의 숫자는 2 개의 청크 (974 * 2 * 7 = 13636 비트)에 적합합니다. 총14193 비트 .
인코딩 된 숫자의 양 |
1 청크 | 2- 청크 | 3 청크 | 총 비트
--------- + ---------- + ---------- + ------------
999 | 0 | 0 | 7025
800 | 180 | 19 | 8551
0 | 974 | 25 | 14193
필요한 공간을 더욱 줄이기 위해 수행 할 수있는 네 가지 추가 최적화를 볼 수 있습니다.
- 세 번째 청크에는 전체 7 비트가 필요하지 않으며 플래그 비트없이 5 비트 만 가능합니다.
- 각 청크에 가장 적합한 크기를 계산하기 위해 숫자의 초기 단계가있을 수 있습니다. 특정 전화 번호부의 경우 첫 번째 청크에 5 + 1 비트, 두 번째 7 + 1 및 세 번째 5 + 1 비트를 사용하는 것이 가장 좋습니다. 그러면 크기가 최소 6 * 999 + 32 = 6026 비트로 줄어들고, 총 3 개의 비트로 구성된 2 세트가 추가되어 청크 1과 2의 크기를 저장합니다 (청크 3의 크기는 필요한 16 비트의 나머지입니다). 6032 비트의!
- 동일한 초기 패스가 기본 100보다 더 나은 예상 증분을 계산할 수 있습니다. 55555-50000에서 시작하는 전화 번호부가있을 수 있으므로 번호 범위가 절반이므로 예상 증분은 50이어야합니다. 또는 비선형 일 수도 있습니다. 분포 (표준 편차) 및 기타 최적의 예상 증분을 사용할 수 있습니다. 이렇게하면 일반적인 분산이 줄어들고 더 작은 첫 번째 청크를 사용할 수 있습니다.
- 첫 번째 단계에서 추가 분석을 수행하여 전화 번호부를 분할 할 수 있으며 각 파티션은 자체 예상 증분 및 청크 크기 최적화를 갖습니다. 이렇게하면 전화 번호부의 매우 균일 한 특정 부분에 대해 더 작은 첫 번째 청크 크기 (소비되는 비트 수 감소)를 허용하고 균일하지 않은 부분에 대해 더 큰 청크 크기 (연속 플래그에 낭비되는 비트 수 감소)를 허용합니다.