問題描述:
輸入: 一個最多包含n個正整數的檔案,每個數都小于n,其中 n = 10^7.如果在輸入檔案中
有任何整數重複出現就是緻命錯誤.沒有其他資料與該整數相關聯.
輸出: 按升序排列的輸入整數的清單
限制: 最多有(大約) 1MB 的記憶體空間可以使用,有充足的磁盤空間可以使用,運作時間最多
幾分鐘,運作時間最多為10s就不需要進一步優化了
問題分析:
顯而易見 說到排序大家第一個必然想到 快速排序,
方案一: 快速排序
那不妨讓我們先計算下快速排序整個文
件所需要的空間大小,假設資料以 32位int型存放
((10^7) * 32) /(8*1024*1024) = 38.14MB
38.14 / 1 = 39 次
是的 我們至少需要 (39 + 1) 次快速排序,需要将資料分40次讀入記憶體.那麼時間複雜度可想
而知.
方案二: 歸并排序
有興趣可以去查一下
方案三: 我了解為 基于hash的排序 下面我詳述一下
算法思想:
1 用 "位圖"(bitmap) 這種資料結構來進行存儲資料.
位圖: 該資料結構描述了一個有限定義域内的稠密集合,其中的每一個元素至多出現一次
并且沒有其他任何資料與該元素相關聯.即使這些條件沒有完全滿足,也可以用有限定義域
内的鍵作為一個表項更複雜的表格索引.
2 類似于hash排序的思想,用位圖存放所需要的記憶體大小為
(10^7)/(8*1024*1024) = 1.19MB
将記憶體空間的需求瞬間縮小到 1.19MB 使一次性讀入成為可能
算法代碼:
以下代碼僅作思想展現,實際意義并不大
#include <iostream>
#include <cmath>
#define MAX 4
using namespace std;
// 初始化字典數組
int Dic[32] = {0};
void InItDic(){
for(int i = 0;i<32;i++)
Dic[i] = pow(2,i);
}
int main(){
// 申請大小為 312500的數組,當然直接申請這麼大的很容易崩潰,不推薦
int array[312500] = {0};
int i;
int Wait[MAX] = {0};
InItDic();
// 生成待排序資料 也可以從硬碟中讀取
for(i=0;i<MAX;i++){
Wait[i] = MAX - i - 1;
}
// 進行排序
/*
具體解析:
一個int有32位,即 312500 * 32 = 10^7
将 待排序數/32 計算出應該存儲這個位的數字編号
将 待排序數%32 計算出存儲在這個數的哪一二進制位
然後将這一位置為1,我在此采用置1的方法是,将表示該位的數
與原數做 按位或 運算
最後按位周遊 得到的就是升序序列
*/
for(i=0;i<MAX;i++)
array[Wait[i]/32] |= Dic[Wait[i]%32];
cout << array[0];
}
// 個人見解 歡迎指正 不勝感激