說到排序,大家第一反應基本上是內排序,是的,演算法嘛,玩的就是記憶體,然而記憶體是有限制的,總有裝不下的那一天,此時就可以來玩玩
外排序,當然在我看來,外排序考驗的是乙個程式設計師的架構能力,而不僅僅侷限於排序這個層次。
一:n路歸併排序
1.概序
我們知道演算法中有一種叫做分治思想,乙個大問題我們可以採取分而治之,各個突破,當子問題解決了,大問題也就ko了,還有一點我們知道
內排序的歸併排序是採用二路歸併的,因為分治後有logn層,每層兩路歸併需要n的時候,最後複雜度為nlogn,那麼外排序我們可以將這個「二」
擴大到m,也就是將乙個大檔案分成m個小檔案,每個小檔案是有序的,然後對應在記憶體中我們開m個優先佇列,每個佇列從對應編號的檔案中讀取
topn條記錄,然後我們從m路佇列中各取乙個數字進入中轉站佇列,並將該數字打上佇列編號標記,當從中轉站出來的最小數字就是我們最後要排
序的數字之一,因為該數字打上了佇列編號,所以方便我們通知對應的編號佇列繼續出數字進入中轉站佇列,可以看出中轉站一直儲存了m個記錄,
當中轉站中的所有數字都出隊完畢,則外排序結束。如果大家有點蒙的話,我再配合一張圖,相信大家就會一目了然,這考驗的是我們的架構能力。
圖中這裡有個batch容器,這個容器我是基於效能考慮的,當batch=n時,我們定時重新整理到檔案中,保證記憶體有足夠的空間。
2.構建
<1> 生成資料
這個基本沒什麼好說的,採用隨機數生成n條記錄。
#region 隨機生成資料
/// /// 隨機生成資料
///執行生成的資料上線
///
public static void createdata(int max)
sw.close();
}#endregion
<2> 切分資料
根據實際情況我們來決定到底要分成多少個小檔案,並且小檔案的資料必須是有序的,小檔案的個數也對應這記憶體中有多少個優先佇列。
#region 將資料進行分份
/// /// 將資料進行分份
/// 每頁要顯示的條數
///
public static int split(int size)
}else
}return pagecount;
}#endregion
<3> 加入佇列
我們知道記憶體佇列存放的只是小檔案的topn條記錄,當記憶體隊列為空時,我們需要再次從小檔案中讀取下一批的topn條資料,然後放入中轉站
繼續進行比較。
#region 將資料加入指定編號佇列
/// /// 將資料加入指定編號佇列
///
/// 佇列編號
/// 檔案中跳過的條數
///
/// 需要每次讀取的條數
public static void addqueue(int i, list> list, ref int skip, int top = 100)
#endregion
<4> 測試
最後我們來測試一下:
資料量:short.maxvalue。
記憶體存放量:1200。
在這種場景下,我們決定每個檔案放1000條,也就有33個小檔案,也就有33個記憶體佇列,每個佇列取top100條,batch=500時重新整理
硬碟,中轉站存放33*2個數字(因為入中轉站時打上了佇列標記),最後記憶體活動最大總數為:sum=33*100+500+66=896<1200。
時間複雜度為n*logn。當然這個「閥值」,我們可以再仔細微調。
public static void main()
//初始化操作,從每個佇列中取出一條記錄,並且在入隊的過程中
//記錄該資料所屬的 「佇列編號」
for (int i = 0; i < list.count; i++)
//預設500條寫入一次檔案
listbatch = new list();
//記錄下次應該從哪乙個佇列中提取資料
int nextindex = 0;
while (queuecontrol.count() > 0)
else}}
//如果彈出的數不為空,則將該數入中轉站
if (nextdata != null)
batch.add(single.level);
//如果batch=500,或者所有的檔案都已經讀取完畢,此時我們要批量刷入資料
if (batch.count == batchcount || allcomplete == pagecount)
sw.close();
batch.clear();}}
console.writeline("恭喜,外排序完畢!");
console.read();
}
經典演算法題每日演練 第十二題 線段樹
這一篇我們來看樹狀陣列的加強版線段樹,樹狀陣列能玩的線段樹一樣可以玩,而且能玩的更好,他們在區間求和,最大,平均 等經典的rmq問題上有著對數時間的優越表現。一 線段樹 線段樹又稱 區間樹 在每個節點上儲存乙個區間,當然區間的劃分採用折半的思想,葉子節點只儲存乙個值,也叫單元節點,所 以最終的構造就...
經典演算法題每日演練 第十九題 雙端佇列
話說大學的時候老師說妹子比工作重要 工作可以再換,妹子這個。所以。這兩個月也就一直忙著fall in love,嗨,慢慢調整心態吧,這篇就選乙個簡單的資料結構聊一聊,話說有很多資料結構都在玩組合拳,比如說 塊狀鍊錶,塊狀陣列,當然還有本篇的雙端佇列,是的,它就是 棧和佇列的組合體。一 概念 我們知道...
經典演算法題每日演練 第十一題 Bitmap演算法
在所有具有效能優化的資料結構中,我想大家使用最多的就是hash表,是的,在具有定位查詢上具有o 1 的常量時間,多麼的簡潔優美,但是在特定的場合下 對10億個不重複的整數進行排序。找出10億個數字中重複的數字。當然我只有普通的伺服器,就算2g的記憶體吧,在這種場景下,我們該如何更好的挑選資料結構和演...