Một giải pháp có thể chỉ vì sự khác biệt giữa 1 megabyte và 1 triệu byte. Có khoảng 2 đến 8093729,5 cách khác nhau để chọn 1 triệu số có 8 chữ số với các số trùng lặp được phép và không quan trọng, do đó, một máy chỉ có 1 triệu byte RAM không có đủ trạng thái để thể hiện tất cả các khả năng. Nhưng 1M (ít hơn 2k cho TCP / IP) là 1022 * 1024 * 8 = 8372224 bit, vì vậy một giải pháp là có thể.
Phần 1, giải pháp ban đầu
Cách tiếp cận này cần nhiều hơn 1M một chút, tôi sẽ tinh chỉnh nó để phù hợp với 1M sau.
Tôi sẽ lưu trữ một danh sách các số được sắp xếp nhỏ gọn trong phạm vi từ 0 đến 99999999 dưới dạng một chuỗi các danh sách con của các số 7 bit. Danh sách con đầu tiên giữ các số từ 0 đến 127, danh sách phụ thứ hai giữ các số từ 128 đến 255, v.v. 100000000/128 chính xác là 781250, vì vậy cần có 781250 danh sách phụ như vậy.
Mỗi danh sách con bao gồm một tiêu đề danh sách con 2 bit, theo sau là phần thân danh sách con. Phần thân danh sách con chiếm 7 bit cho mỗi mục nhập danh sách phụ. Tất cả các danh sách con được nối với nhau và định dạng cho phép biết nơi một danh sách con kết thúc và tiếp theo bắt đầu. Tổng dung lượng cần thiết cho danh sách được điền đầy đủ là 2 * 781250 + 7 * 1000000 = 8562500 bit, khoảng 1.021 M-byte.
4 giá trị tiêu đề danh sách con có thể là:
00 sách con trống, không có gì sau.
01 Singleton, chỉ có một mục trong danh sách con và 7 bit tiếp theo giữ nó.
10 Danh sách con giữ ít nhất 2 số riêng biệt. Các mục được lưu trữ theo thứ tự không giảm, ngoại trừ mục cuối cùng nhỏ hơn hoặc bằng mục đầu tiên. Điều này cho phép kết thúc danh sách con được xác định. Ví dụ, các số 2,4,6 sẽ được lưu trữ dưới dạng (4,6,2). Các số 2,2,3,4,4 sẽ được lưu trữ dưới dạng (2,3,4,4,2).
11 Danh sách con giữ 2 hoặc nhiều lần lặp lại của một số. 7 bit tiếp theo cho số. Sau đó đến 0 hoặc nhiều hơn các mục 7 bit có giá trị 1, tiếp theo là mục 7 bit có giá trị 0. Độ dài của thân danh sách phụ quy định số lần lặp lại. Ví dụ: các số 12,12 sẽ được lưu trữ dưới dạng (12,0), các số 12,12,12 sẽ được lưu trữ dưới dạng (12,1,0), 12,12,12,12 sẽ là (12,1 , 1,0) và như vậy.
Tôi bắt đầu với một danh sách trống, đọc một loạt các số và lưu trữ chúng dưới dạng số nguyên 32 bit, sắp xếp các số mới tại chỗ (có thể sử dụng heapsort), sau đó hợp nhất chúng vào một danh sách sắp xếp nhỏ gọn mới. Lặp lại cho đến khi không còn số nào để đọc, sau đó đi bộ danh sách nhỏ gọn một lần nữa để tạo đầu ra.
Dòng bên dưới đại diện cho bộ nhớ ngay trước khi bắt đầu hoạt động hợp nhất danh sách. "O" là vùng chứa các số nguyên 32 bit được sắp xếp. "X" là khu vực chứa danh sách nhỏ gọn cũ. Dấu "=" là phòng mở rộng cho danh sách nhỏ gọn, 7 bit cho mỗi số nguyên trong "O" s. Các chữ "Z" là các chi phí ngẫu nhiên khác.
ZZZOOOOOOOOOOOOOOOOOOOOOOOOOO==========XXXXXXXXXXXXXXXXXXXXXXXXXX
Thói quen hợp nhất bắt đầu đọc ở "O" ngoài cùng bên trái và ở "X" ngoài cùng bên trái, và bắt đầu viết ở ngoài cùng "=". Con trỏ ghi không bắt được con trỏ đọc danh sách nhỏ gọn cho đến khi tất cả các số nguyên mới được hợp nhất, bởi vì cả hai con trỏ đều tăng 2 bit cho mỗi danh sách con và 7 bit cho mỗi mục trong danh sách rút gọn cũ và có đủ chỗ cho Các mục 7 bit cho các số mới.
Phần 2, nhồi nhét nó vào 1M
Để Bóp giải pháp trên thành 1M, tôi cần làm cho định dạng danh sách nhỏ gọn hơn một chút. Tôi sẽ loại bỏ một trong các loại danh sách phụ, do đó sẽ chỉ có 3 giá trị tiêu đề danh sách phụ khác nhau có thể. Sau đó, tôi có thể sử dụng "00", "01" và "1" làm giá trị tiêu đề của danh sách phụ và lưu một vài bit. Các loại danh sách con là:
Một danh sách con trống, không có gì sau.
B Singleton, chỉ có một mục trong danh sách con và 7 bit tiếp theo giữ nó.
C Danh sách con giữ ít nhất 2 số riêng biệt. Các mục được lưu trữ theo thứ tự không giảm, ngoại trừ mục cuối cùng nhỏ hơn hoặc bằng mục đầu tiên. Điều này cho phép kết thúc danh sách con được xác định. Ví dụ, các số 2,4,6 sẽ được lưu trữ dưới dạng (4,6,2). Các số 2,2,3,4,4 sẽ được lưu trữ dưới dạng (2,3,4,4,2).
D Danh sách con bao gồm 2 hoặc nhiều lần lặp lại của một số.
3 giá trị tiêu đề danh sách phụ của tôi sẽ là "A", "B" và "C", vì vậy tôi cần một cách để thể hiện danh sách phụ loại D.
Giả sử tôi có tiêu đề danh sách phụ loại C theo sau là 3 mục, chẳng hạn như "C [17] [101] [58]". Đây không thể là một phần của danh sách con loại C hợp lệ như được mô tả ở trên, vì mục nhập thứ ba ít hơn mục thứ hai nhưng nhiều hơn mục thứ nhất. Tôi có thể sử dụng kiểu cấu trúc này để thể hiện một danh sách con loại D. Về mặt bit, bất cứ nơi nào tôi có "C {00 ?????} {1 ??????} {01 ?????}" là một danh sách con loại C không thể. Tôi sẽ sử dụng điều này để đại diện cho một danh sách con bao gồm 3 hoặc nhiều lần lặp lại của một số. Hai từ 7 bit đầu tiên mã hóa số (các bit "N" bên dưới) và được theo sau bởi 0 hoặc nhiều hơn {0100001} từ theo sau là từ {0100000}.
For example, 3 repetitions: "C{00NNNNN}{1NN0000}{0100000}", 4 repetitions: "C{00NNNNN}{1NN0000}{0100001}{0100000}", and so on.
Điều đó chỉ để lại danh sách chứa chính xác 2 lần lặp lại của một số duy nhất. Tôi sẽ đại diện cho những người có mẫu danh sách phụ loại C không thể khác: "C {0 ??????} {11 ?????} {10 ?????}". Có rất nhiều chỗ cho 7 bit của số trong 2 từ đầu tiên, nhưng mẫu này dài hơn danh sách con mà nó đại diện, khiến mọi thứ phức tạp hơn một chút. Năm dấu hỏi ở cuối có thể được coi là không phải là một phần của mẫu, vì vậy tôi có: "C {0NNNNNN} {11N ????} 10" làm mẫu của tôi, với số được lặp lại được lưu trữ trong "N "S. Đó là 2 bit quá dài.
Tôi sẽ phải mượn 2 bit và trả lại từ 4 bit không sử dụng trong mẫu này. Khi đọc, khi gặp "C {0NNNNNN} {11N00AB} 10", xuất ra 2 trường hợp của số trong "N", ghi đè lên "10" ở cuối bằng các bit A và B và tua lại con trỏ đọc bằng 2 chút ít. Đọc phá hủy là ok cho thuật toán này, vì mỗi danh sách nhỏ gọn chỉ được đi một lần.
Khi viết một danh sách con gồm 2 lần lặp lại của một số duy nhất, hãy viết "C {0NNNNNN} 11N00" và đặt bộ đếm bit đã mượn thành 2. Tại mỗi lần ghi mà bộ đếm bit mượn là khác không, nó sẽ bị giảm cho mỗi bit được ghi và "10" được viết khi bộ đếm chạm 0. Vì vậy, 2 bit tiếp theo được viết sẽ đi vào các khe A và B, và sau đó "10" sẽ được thả vào cuối.
Với 3 giá trị tiêu đề danh sách phụ được biểu thị bằng "00", "01" và "1", tôi có thể gán "1" cho loại danh sách phụ phổ biến nhất. Tôi sẽ cần một bảng nhỏ để ánh xạ các giá trị tiêu đề của danh sách phụ thành các loại danh sách phụ và tôi sẽ cần một bộ đếm xuất hiện cho từng loại danh sách phụ để tôi biết ánh xạ tiêu đề danh sách phụ tốt nhất là gì.
Trường hợp xấu nhất đại diện tối thiểu của một danh sách nhỏ gọn đầy đủ xảy ra khi tất cả các loại danh sách con đều phổ biến như nhau. Trong trường hợp đó, tôi tiết kiệm 1 bit cho mỗi 3 tiêu đề danh sách phụ, vì vậy kích thước danh sách là 2 * 781250 + 7 * 1000000 - 781250/3 = 8302083.3 bit. Làm tròn đến một ranh giới từ 32 bit, đó là 8302112 bit, hoặc 1037764 byte.
1M trừ đi 2k cho trạng thái TCP / IP và bộ đệm là 1022 * 1024 = 1046528 byte, để lại cho tôi 8764 byte để chơi.
Nhưng những gì về quá trình thay đổi ánh xạ tiêu đề danh sách phụ? Trong bản đồ bộ nhớ bên dưới, "Z" là chi phí ngẫu nhiên, "=" là không gian trống, "X" là danh sách nhỏ gọn.
ZZZ=====XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bắt đầu đọc ở "X" ngoài cùng bên trái và bắt đầu viết ở ngoài cùng "=" và làm việc bên phải. Khi hoàn thành, danh sách nhỏ gọn sẽ ngắn hơn một chút và nó sẽ ở cuối bộ nhớ sai:
ZZZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=======
Vì vậy, sau đó tôi sẽ cần chuyển nó sang bên phải:
ZZZ=======XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Trong quy trình thay đổi ánh xạ tiêu đề, tối đa 1/3 tiêu đề danh sách phụ sẽ được thay đổi từ 1 bit sang 2 bit. Trong trường hợp xấu nhất, tất cả sẽ nằm ở đầu danh sách, vì vậy tôi sẽ cần ít nhất 781250/3 bit lưu trữ miễn phí trước khi bắt đầu, điều này đưa tôi trở lại các yêu cầu bộ nhớ của phiên bản trước của danh sách rút gọn: (
Để giải quyết vấn đề đó, tôi sẽ chia 781250 danh sách phụ thành 10 nhóm danh sách phụ gồm 78125 danh sách phụ mỗi nhóm. Mỗi nhóm có ánh xạ tiêu đề danh sách con độc lập riêng. Sử dụng các chữ cái từ A đến J cho các nhóm:
ZZZ=====AAAAAABBCCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
Mỗi nhóm danh sách phụ thu nhỏ hoặc giữ nguyên trong khi thay đổi ánh xạ tiêu đề danh sách phụ:
ZZZ=====AAAAAABBCCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAA=====BBCCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABB=====CCCCDDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCC======DDDDDEEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDD======EEEFFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEE======FFFGGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFF======GGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGG=======HHIJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHH=======IJJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHHI=======JJJJJJJJJJJJJJJJJJJJ
ZZZAAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ=======
ZZZ=======AAAAAABBCCCDDDDDEEEFFFGGGGGGGGGGHHIJJJJJJJJJJJJJJJJJJJJ
Trường hợp xấu nhất mở rộng tạm thời của một nhóm danh sách con trong khi thay đổi ánh xạ là 78125/3 = 26042 bit, dưới 4k. Nếu tôi cho phép 4k cộng với 1037764 byte cho danh sách nhỏ gọn được điền đầy đủ, thì tôi sẽ để lại 8764 - 4096 = 4668 byte cho "Z" trong bản đồ bộ nhớ.
Đó là rất nhiều cho 10 bảng ánh xạ tiêu đề danh sách phụ, 30 số lần xuất hiện tiêu đề danh sách phụ và một số bộ đếm, con trỏ và bộ đệm nhỏ khác mà tôi cần, và không gian tôi đã sử dụng mà không nhận thấy, như không gian ngăn xếp cho địa chỉ trả lời cuộc gọi chức năng và biến cục bộ.
Phần 3, sẽ mất bao lâu để chạy?
Với danh sách rút gọn trống, tiêu đề danh sách 1 bit sẽ được sử dụng cho danh sách con trống và kích thước bắt đầu của danh sách sẽ là 781250 bit. Trong trường hợp xấu nhất, danh sách tăng 8 bit cho mỗi số được thêm vào, do đó, cần có 32 + 8 = 40 bit không gian trống cho mỗi số 32 bit được đặt ở đầu bộ đệm danh sách, sau đó được sắp xếp và hợp nhất. Trong trường hợp xấu nhất, việc thay đổi ánh xạ tiêu đề danh sách phụ sẽ dẫn đến việc sử dụng khoảng trắng của các mục 2 * 781250 + 7 * - 781250/3 bit.
Với chính sách thay đổi ánh xạ tiêu đề danh sách phụ sau mỗi lần hợp nhất thứ năm một khi có ít nhất 800000 số trong danh sách, trường hợp xấu nhất sẽ liên quan đến tổng cộng khoảng 30 triệu hoạt động đọc và viết danh sách nhỏ gọn.
Nguồn:
http://nick.cleaton.net/ramsortsol.html