해결책은 1MB와 100 만 바이트의 차이로 인해 가능합니다. 8093729.5에 대해 중복이 허용 된 백만 개의 8 자리 숫자를 선택하고 중요하지 않은 순서로 약 2 개의 방법이 있으므로, 백만 바이트의 RAM이있는 머신에는 모든 가능성을 나타내는 데 충분한 상태가 없습니다. 그러나 1M (TCP / IP의 경우 2k 미만)은 1022 * 1024 * 8 = 8372224 비트이므로 솔루션이 가능합니다.
1 부, 초기 솔루션
이 방법은 1M보다 조금 더 필요합니다. 나중에 1M에 맞도록 수정하겠습니다.
7 비트 숫자의 하위 목록 시퀀스로 0에서 99999999 범위의 간단한 정렬 된 숫자 목록을 저장합니다. 첫 번째 서브리스트는 0에서 127까지의 숫자를 보유하고, 두 번째 서브리스트는 128에서 255까지의 숫자를 보유합니다. 100000000/128은 정확히 781250이므로 781250의 이러한 서브리스트가 필요합니다.
각 하위 목록은 2 비트 하위 목록 헤더와 하위 목록 본문으로 구성됩니다. 서브리스트 본문은 서브리스트 항목 당 7 비트를 차지합니다. 하위 목록은 모두 함께 연결되며 형식을 사용하면 한 하위 목록이 끝나고 다음이 시작되는 위치를 알 수 있습니다. 완전히 채워진 목록에 필요한 총 스토리지는 2 * 781250 + 7 * 1000000 = 8562500 비트이며 이는 약 1.021MB입니다.
4 가지 가능한 서브리스트 헤더 값은 다음과 같습니다.
00 빈 서브리스트, 다음은 아무것도 없습니다.
01 싱글 톤, 서브리스트에는 단 하나의 엔트리 만이 있고 다음 7 비트는 그것을 유지합니다.
10 하위 목록에는 최소한 2 개의 고유 숫자가 있습니다. 마지막 항목이 첫 번째 항목보다 작거나 같은 것을 제외하고 항목은 감소하지 않는 순서로 저장됩니다. 이를 통해 서브리스트의 끝을 식별 할 수 있습니다. 예를 들어 숫자 2,4,6은 (4,6,2)로 저장됩니다. 숫자 2,2,3,4,4는 (2,3,4,4,2)로 저장됩니다.
11 서브리스트는 단일 숫자의 반복을 두 번 이상 보유합니다. 다음 7 비트는 숫자를 나타냅니다. 그런 다음 값이 1 인 7 비트 항목이 0 개 이상이고 값이 0 인 7 비트 항목이옵니다. 하위 목록 본문의 길이는 반복 횟수를 나타냅니다. 예를 들어 숫자 12,12는 (12,0)으로, 숫자 12,12,12는 (12,1,0)으로, 12,12,12,12는 (12,1)로 저장됩니다. , 1,0) 등입니다.
빈 목록으로 시작하여 많은 수의 숫자를 읽고 32 비트 정수로 저장하고 새 숫자를 제자리에 정렬하고 (아마도 힙 정렬을 사용하여) 새로운 소형 정렬 목록으로 병합합니다. 읽을 숫자가 더 이상 없을 때까지 반복 한 다음 요약 목록을 한 번 더 걸어 출력을 생성하십시오.
아래 줄은 목록 병합 작업이 시작되기 직전에 메모리를 나타냅니다. "O"는 정렬 된 32 비트 정수를 보유하는 영역입니다. "X"는 이전 컴팩트 목록을 보유한 영역입니다. "="부호는 콤팩트 목록의 확장 공간이며 "O"의 각 정수마다 7 비트입니다. "Z"는 다른 임의의 오버 헤드입니다.
ZZZOOOOOOOOOOOOOOOOOOOOOOOOOO==========XXXXXXXXXXXXXXXXXXXXXXXXXX
병합 루틴은 맨 왼쪽 "O"및 맨 왼쪽 "X"에서 읽기 시작하고 맨 왼쪽 "="에서 쓰기 시작합니다. 쓰기 포인터는 모든 새로운 정수가 병합 될 때까지 컴팩트 목록 읽기 포인터를 포착하지 못합니다. 두 포인터는 각각의 하위 목록에 대해 2 비트 씩, 이전 컴팩트 목록에있는 각 항목에 대해 7 비트 씩 앞당겨지기 때문입니다. 새 숫자에 대한 7 비트 항목
Part 2, 1M으로 짜다
위의 솔루션을 1M로 짜려면 압축 목록 형식을 좀 더 압축해야합니다. 하위 목록 유형 중 하나를 제거하여 가능한 3 개의 다른 하위 목록 헤더 값이 있습니다. 그런 다음 "00", "01"및 "1"을 하위 목록 헤더 값으로 사용하고 몇 비트를 저장할 수 있습니다. 하위 목록 유형은 다음과 같습니다.
빈 하위 목록, 다음은 아무것도 없습니다.
B 싱글 톤의 경우, 서브리스트에 단 하나의 항목 만 있고 다음 7 비트가이를 보유합니다.
C 하위 목록에는 최소 2 개의 고유 숫자가 있습니다. 마지막 항목이 첫 번째 항목보다 작거나 같은 것을 제외하고 항목은 감소하지 않는 순서로 저장됩니다. 이를 통해 서브리스트의 끝을 식별 할 수 있습니다. 예를 들어 숫자 2,4,6은 (4,6,2)로 저장됩니다. 숫자 2,2,3,4,4는 (2,3,4,4,2)로 저장됩니다.
D 서브리스트는 단일 숫자의 두 번 이상의 반복으로 구성됩니다.
내 3 개의 서브리스트 헤더 값은 "A", "B"및 "C"가되므로 D- 타입 서브리스트를 나타내는 방법이 필요합니다.
"C [17] [101] [58]"과 같이 C- 타입 서브리스트 헤더 뒤에 3 개의 항목이 있다고 가정합니다. 세 번째 항목은 두 번째 항목보다 작지만 첫 번째 항목보다 많기 때문에 위에서 설명한대로 유효한 C 유형 하위 목록에 속할 수 없습니다. 이 유형의 구성을 사용하여 D 유형 하위 목록을 나타낼 수 있습니다. 비트 용어로, "C {00 ?????} {1 ??????} {01 ?????}"는 불가능한 C- 타입 서브리스트입니다. 이것을 사용하여 단일 숫자의 3 회 이상의 반복으로 구성된 하위 목록을 나타냅니다. 처음 2 개의 7 비트 단어는 숫자 (아래 "N"비트)를 인코딩하고 0 개 이상의 {0100001} 단어 다음에 {0100000} 단어가옵니다.
For example, 3 repetitions: "C{00NNNNN}{1NN0000}{0100000}", 4 repetitions: "C{00NNNNN}{1NN0000}{0100001}{0100000}", and so on.
단 하나의 숫자를 정확히 2 번 반복하는 목록 만 남습니다. 또 다른 불가능한 C- 타입 서브리스트 패턴 인 "C {0 ??????} {11 ?????} {10 ?????}"를 표현하겠습니다. 처음 두 단어에는 숫자의 7 비트를위한 충분한 공간이 있지만이 패턴은 그것이 나타내는 하위 목록보다 길기 때문에 조금 더 복잡합니다. 끝에있는 5 개의 물음표는 패턴의 일부가 아닌 것으로 간주 될 수 있으므로 "C {0NNNNNN} {11N ????} 10"을 패턴으로 사용하고 반복되는 숫자는 "N에 저장됩니다. "에스. 2 비트가 너무 깁니다.
이 패턴에서 2 비트를 빌려서 사용하지 않은 4 비트에서 갚아야합니다. 읽을 때 "C {0NNNNNN} {11N00AB} 10"이 발생하면 "N"에있는 숫자의 인스턴스 2 개를 출력하고 끝에 A와 B로 "10"을 덮어 쓰고 읽기 포인터를 2만큼 되감습니다. 비트. 각 컴팩트 목록이 한 번만 걷기 때문에이 알고리즘에 대한 파괴적인 읽기가 가능합니다.
단일 숫자의 두 번 반복되는 서브리스트를 작성할 때 "C {0NNNNNN} 11N00"을 쓰고 빌린 비트 카운터를 2로 설정하십시오. 빌린 비트 카운터가 0이 아닌 모든 쓰기에서 기록 된 각 비트에 대해 감소합니다. 카운터가 0에 도달하면 "10"이 기록됩니다. 따라서 다음 2 비트는 슬롯 A와 B로 들어가고 "10"은 끝으로 떨어집니다.
"00", "01"및 "1"로 표시되는 3 개의 하위 목록 헤더 값을 사용하여 가장 인기있는 하위 목록 유형에 "1"을 할당 할 수 있습니다. 하위 목록 헤더 값을 하위 목록 유형에 매핑하려면 작은 테이블이 필요하며 최상의 하위 목록 헤더 매핑이 무엇인지 알 수 있도록 각 하위 목록 유형마다 발생 카운터가 필요합니다.
모든 서브리스트 유형이 동일하게 인기가있을 때 완전히 채워진 컴팩트 목록의 최악의 경우 최소 표시가 발생합니다. 이 경우 3 개의 하위 목록 헤더마다 1 비트를 저장하므로 목록 크기는 2 * 781250 + 7 * 1000000-781250/3 = 8302083.3 비트입니다. 32 비트 워드 경계, 즉 8302112 비트 또는 1037764 바이트로 반올림합니다.
1M에서 TCP / IP 상태 및 버퍼의 2k를 뺀 값은 1022 * 1024 = 1046528 바이트이므로 8764 바이트를 사용할 수 있습니다.
그러나 서브리스트 헤더 매핑을 변경하는 프로세스는 어떻습니까? 아래 메모리 맵에서 "Z"는 임의의 오버 헤드이고 "="는 여유 공간이며 "X"는 간단한 목록입니다.
ZZZ=====XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
가장 왼쪽 "X"에서 읽기 시작하고 가장 왼쪽 "="에서 쓰기 시작하고 오른쪽으로 작업하십시오. 완료되면 압축 목록이 약간 짧아지고 메모리의 잘못된 끝에있을 것입니다.
ZZZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=======
그런 다음 오른쪽으로 분류해야합니다.
ZZZ=======XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
헤더 맵핑 변경 프로세스에서 서브리스트 헤더의 최대 1/3이 1 비트에서 2 비트로 변경됩니다. 최악의 경우 이들은 모두 목록의 선두에 있기 때문에 시작하기 전에 최소 781250/3 비트의 무료 저장 공간이 필요하므로 이전 목록의 압축 목록의 메모리 요구 사항으로 되돌아갑니다. (
이 문제를 해결하기 위해 781250 하위 목록을 각각 78125 개의 하위 목록으로 구성된 10 개의 하위 목록 그룹으로 나누겠습니다. 각 그룹에는 고유 한 독립적 인 서브리스트 헤더 매핑이 있습니다. 그룹에 문자 A-J 사용 :
ZZZ=====AAAAAABBCCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
하위 목록 헤더 매핑 변경 중에 각 하위 목록 그룹이 축소되거나 동일하게 유지됩니다.
ZZZ=====AAAAAABBCCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAA=====BBCCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABB=====CCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCC======DDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDD======EEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEE======FFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFF======GGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGG=======HHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHH=======IJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHHI=======JJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ=======
ZZZ=======AAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
매핑 변경 중 하위 목록 그룹의 최악의 임시 확장은 4k 미만에서 78125/3 = 26042 비트입니다. 완전히 채워진 컴팩트 목록에 4k와 1037764 바이트를 허용하면 메모리 맵의 "Z"에 대해 8764-4096 = 4668 바이트가 남습니다.
10 개의 하위 목록 헤더 매핑 테이블, 30 개의 하위 목록 헤더 발생 횟수 및 필요한 다른 카운터, 포인터 및 작은 버퍼 및 함수 호출 반환 주소의 스택 공간 및 지역 변수.
3 부, 얼마나 오래 걸립니까?
빈 컴팩트 목록의 경우 1 비트 목록 헤더가 빈 하위 목록에 사용되고 목록의 시작 크기는 781250 비트입니다. 최악의 경우 목록은 추가 된 각 숫자에 대해 8 비트로 증가하므로 32 비트 숫자 각각이 목록 버퍼의 맨 위에 배치 된 다음 정렬 및 병합하려면 32 + 8 = 40 비트의 여유 공간이 필요합니다. 최악의 경우, 서브리스트 헤더 맵핑을 변경하면 2 * 781250 + 7 * 항목-781250/3 비트의 공간 사용량이 발생합니다.
목록에 최소 800000 개의 숫자가 있으면 5 번의 병합 후마다 서브리스트 헤더 매핑을 변경하는 정책으로 최악의 경우 약 30M의 간단한 목록 읽기 및 쓰기 작업이 필요합니다.
출처:
http://nick.cleaton.net/ramsortsol.html