編程珠璣第二版第一章就有類似的問題,問題描述如下:
有最多1000萬條不同的整型數據存在於硬盤的文件中(數據不超過最大值),如何在1M內存的情況下對其進行盡可能快的排序。
數據特征:單個數據<=1000萬、不同的(沒有重復)、整型(int,4B) 要求:1M內存、盡可能快 分析:1MB = 1*1024*1024 B 能存儲大於25萬個int類型的整數。所以每次我們可以排序25萬條記錄,一共排序40次。
(1)一個簡單的思路是讀1000萬條1次,對第i個25萬條數據進行排序,並將排好的結果存成外部文件i(這里可以用常見的內部排序,如快排),最后我們生成了40個排好序的外部文件,然后對這40個文件進行歸並排序輸出成1個文件。
(2)更好的思路是位向量排序,我們可以申請一個1千萬長度的位向量bit[10000000],所有位設置為0,順序讀取待排序文件,每讀入一個數i,便將bit[i]置為1。當所有數據讀入完成,便對 bit做從頭到尾的遍歷,如果bit[i]=1,則輸出i到文件,當遍歷完成,文件則已排好序。
這個思路和桶排序一樣,算法的關鍵是位向量。對於不支持bit數據結構的語言我們可以自己實現位操作,int是32位的,所以我們需要[1千萬/32+1]個int類型存儲,大約1.2M。(雖然差點不符合題目的要求,但是不失為一種更好的解題思路)。
將第i位置為1的時候可以用如下操作:
a[i/32] | (1 << (i%32));
第i位肯定在i/32個int上,i%32是偏移量,然后通過按位或來將特定位置1。(不明白的可以了解一下位計算)
為了計算速度更快,上述公式可以完全由位運算替代:
a[i >>5] |= (1 << (i & 31));
總結
對於大的數量級的排序,基本思路是分而治之的思想,位向量方法雖然效率很高,但是要注意一些限制條件(數據不能重復、不適合稀疏的數據分布等)。
編程珠璣中的例子是int型的數據排序,實際我們面臨的問題可能不會這么簡單,例如需要對復雜數據類型進行排序(對象),我們可以讓對象實現compareTo,重寫hashcode、equals等等。