外部排序剖析 以磁帶為例

2021-08-14 12:48:42 字數 3017 閱讀 5007

本文總結自《資料結構與演算法分析(c++語言描述)》第四版第7章外部排序的內容。

所謂外部,是指磁碟、磁帶、光碟等外部儲存介質;那麼內部相應指的是記憶體。

顯然,他們之間的重要區別就是速度和容量,外存慢容量超大,記憶體超快容量小;

因此,當需要排序的資料量超過記憶體所能容納的大小時,普通的排序演算法比如快速排序,便無用武之地。本質的原因就是記憶體可以常數時間訪問乙個元素,但是外存比如硬碟,會有轉動磁碟和移動磁頭等不容忽視的時間開銷。

外排序(external sorting)是指能夠處理極大量資料的排序演算法。通常來說,外排序處理的資料不能一次裝入記憶體,只能放在讀寫較慢的外儲存器(通常是硬碟)上。外排序通常採用的是一種_「排序-歸併」_的策略。在排序階段,先讀入能放在記憶體中的資料量,將其排序輸出到乙個臨時檔案,依此進行,將待排序資料組織為多個有序的臨時檔案。爾後在歸併階段將這些臨時檔案組合為乙個大的有序檔案,也即排序結果。

3.1 概念先知

排序:普通的內部排序演算法,比如快速排序;

歸併:指的是將兩個已經排序的序列合併成乙個序列的操作,即歸併操作;

3.2 以磁帶的 2 路合合併外排為例

3.2.1 假設

記憶體大小受限,因此假設它的大小只能容納 m=3 個記錄;

有4盤磁帶,分別為 ta1, ta2, tb1, tb2;

待排資料預先儲存在 ta1;

3.2.2 外部排序過程詳解

(1)資料原始狀態

(2)每次從 ta1 讀取 m 個記錄到記憶體中,排序完成,分別按順串輸出到 tbn;得到如下結果,總共 5 個順串, tb1 三個, tb2 兩個;

(3)依次從 tb1 和 tb2 讀取乙個順串進行合併,並輸出到 ta*,得到如下結果,總共三個順串,ta1 兩個,ta2 乙個;

(4)重複(3)的做法,即第二趟合併,得到如下結果,兩個順串,tb1 和 tb2 各乙個;

(5)繼續第三趟合併,得到最終結果,如下,

多路合併的作用在於減少外部排序所需的趟數,從 ⌈log(n/m)⌉ 降至 ⌈log k(n/m)⌉ (即以 k 為底,n/m 為真數),k>=3,n 指總記錄數;多相合併則解決多路合併中對磁碟需求量大的問題,從 2k 數量的磁帶降至 k+1。

多路合併與 2 路合併的方式基本相似,相信大家注意到了,兩者唯一的區別是在合併上,2 路合併只需比較兩個數從而可以得到最小值,但是多路合併有 k 個數,即需從 k 個數取出最小值,因此採取的合理方式是用**最小堆**來實現,這樣每次通過對最小堆執行 deletemin 操作,來逐一獲取最小值。

2.1 3路合併過程詳解

(1)資料初始狀態

(2)依次從 ta1 中讀取 m 個記錄,排序後按順串依次輸出到 tbn,得到如下結果,tb1 兩個順串,tb2兩個順串,tb3 乙個順串;

(3)第一趟合併結果,此時 3 個輸出磁帶未用完,只有兩個順串,ta1 乙個順串, ta2 乙個順串, 如下;

(4)第二趟合併,即最終外部排序結果,如下;

現在討論如何將多路排序的 2k 盤磁帶轉換為 k+1 盤;這裡以 2 路合併為例,通過 3 盤磁帶實現。本節關心每趟合併中順串的數量,而不關心具體的記錄

3.1 假設

3 盤磁帶分別為,t1,t2,t3,

輸入資料在 t1 上,它將輸出共 34 個順串,

以兩種方式對 t2 和 t3 分配順串數量:(1)17 和 17;(2) 21 和 13;

3.2 分析

節省磁碟需要的犧牲就是增加合併總的趟數,多相合併中總趟數會因初始順串數量分配方式不同而產生較大差異,這裡初始順串分配方式指將原始記錄在記憶體排序完成後輸出到空磁帶上的過程。下面是**,注意,每一趟順串的記錄數量不一樣,

(1)17 和 17 的方式,總共 12 趟,拆開的原因在於,把結果合併到乙個磁帶上了,此時無法做合併操作,只能先拆分再合併。

(2)21 和 13 的方式,總共 8 趟,

3.3 總結

大家有興趣可以自己在紙上畫出初始分配方式為 22 和 12 的過程圖,從上面**過程基本可以知道,初始的順串數量分配方式對最終外部排序需要的趟數有較大的影響。

但是有一種最優的分配方式,那就是斐波拉契數列,2 路合併就分配為 fn-1 和 fn-2, 如果無法分成兩個斐波拉契數,則通過補充虛順串(長度為0的順串)來實現。拓展到 k 路合併,則需要 k 階斐波那契數列來分配順串。

k 階斐波那契數列:

其初始條件:

從上面的總結分析可以看出,外部排序比內部排序對裝置的依賴性更強。比如效能,以及資料讀取方式(e.g. 硬碟和磁帶)等。

高階部分還有替換選擇。

三種基本排序 以公升序為例

接下來上 include intmain void for j 0 jprintf 5d a j printf n n return 0 for i 0 i1 i n個數,總共需要進行n 1次 if 1 f f為1說明沒進行過冒泡,說明序列有序 break 若序列有序,則跳出排序即可 接下來上 in...

迭代和遞迴的區別 以快速排序演算法為例

這是一篇講解快速排序演算法的文章 排序演算法有很多種,例如氣泡排序法,堆排序法,簡單排序法以及快速排序法等。其中,快速排序演算法的時間複雜度為o nlogn 氣泡排序演算法的時間複雜度為o n 2 故快速排序演算法比較快,但是其不穩定。穩定性是指 假定在待排序的記錄序列中,存在多個具有相同的關鍵字的...

jBPM持久化(以MySQL為例)

1 在mysql裡新建一資料庫,名為jbpm create database jbpm 名字可以任意,後面要用到。3 將mysql的jdbc驅動mysql connector.jar拷貝到jbpm資料夾的lib mysql下,沒有mysql資料夾則新建乙個。4 在jbpm資料夾的src resour...