外部排序指的是大文件的排序,即待排序的記錄存儲在外存儲器上,待排序的文件無法一次裝入內存,需要在內存和外部存儲器之間進行多次數據交換,以達到排序整個文件的目的。外部排序最常用的算法是多路歸並排序,即將原文件分解成多個能夠一次性裝入內存的部分,分別把每一部分調入內存完成排序。然後,對已經排序的子文件進行歸並排序。
假設我們要寫一個外部排序程序。現在要討論的是對已經排序的子文件進行歸並排序。
下面是外部排序歸並階段的代碼片段:
01: class ExternalSorting 02: { 03: void Merge(string inputFileName1, string inputFileName2, string outputFileName) 04: { 05: using (var reader1 = new StreamReader(inputFileName1)) 06: { 07: using (var reader2 = new StreamReader(inputFileName2)) 08: { 09: using (var writer = new StreamWriter(outputFileName)) 10: { 11: Merge(reader1, reader2, writer); 12: } 13: } 14: } 15: } 16: 17: void Merge(TextReader reader1, TextReader reader2, TextWriter writer) 18: { 19: var s1 = reader1.ReadLine(); 20: var s2 = reader2.ReadLine(); 21: while (s1 != null || s2 != null) 22: { 23: if (Compare(s1, s2) <= 0) StepIt(ref s1, reader1, writer); 24: else StepIt(ref s2, reader2, writer); 25: } 26: } 27: 28: int Compare(string s1, string s2) 29: { 30: if (s1 == null && s2 == null) throw new ArgumentException("s1 和 s2 不能同時為 null"); 31: if (s1 == null) return 1; 32: if (s2 == null) return -1; 33: return string.Compare(s1, s2); 34: } 35: 36: void StepIt(ref string s, TextReader reader, TextWriter writer) 37: { 38: writer.WriteLine(s); 39: s = reader.ReadLine(); 40: } 41: }
上述代碼中的第 05 到 14 行的三個 using 語句逐個嵌套,依次縮進,是不是很難看?
注意,上述代碼中第 33 行可以替換為你想要的比較大小的方法,以便按照不同的關鍵字進行排序。
我們知道,可以將多個對象與 using 語句一起使用,但必須在 using 語句中聲明這些對象。因此,我們可以將上述的第 05 到 14 行的代碼重構如下:
1: using (TextReader reader1 = new StreamReader(inputFileName1), 2: reader2 = new StreamReader(inputFileName2)) 3: { 4: using (TextWriter writer = new StreamWriter(outputFileName)) 5: { 6: Merge(reader1, reader2, writer); 7: } 8: }
但是還是有兩個嵌套的 using 語句,不爽。
我們還知道,C# 編譯器實際上將 using 語句轉化為 try - finally 塊。那麼我們繼續進行重構:
01: TextReader reader1 = null; 02: TextReader reader2 = null; 03: TextWriter writer