經典演算法題每日演練 第十八題 外排序

2021-09-23 21:45:56 字數 2535 閱讀 7793

說到排序,大家第一反應基本上是內排序,是的,演算法嘛,玩的就是記憶體,然而記憶體是有限制的,總有裝不下的那一天,此時就可以來玩玩

外排序,當然在我看來,外排序考驗的是乙個程式設計師的架構能力,而不僅僅侷限於排序這個層次。

一: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的記憶體吧,在這種場景下,我們該如何更好的挑選資料結構和演...