[英]C# N way merge for external sort
什么是為N個排序文件實現N路合並的最佳方法?
假設我有9個已排序的文件,每個文件有10個記錄? 如何合並這些文件以創建包含90個已排序記錄的大文件?
我假設你的例子中可能會有更多的數據。 如果您可以同時打開所有文件,則可以使用此算法:
請注意,您不必一次將所有文件讀入內存,因此如果您有合理數量的大文件,這將很有效,但如果您有大量小文件則不行。
如果您有許多小文件,則應將它們合並為組以為每個組創建單個輸出文件,然后重復此過程以合並這些新組。
在C#中,您可以使用例如SortedDictionary
來實現優先級隊列。
在另一個答案中解決評論:
如果您有可變數量的文件,這就是我要做的。 這只是一個草圖,以實現這個想法; 這段代碼沒有編譯,我的方法名稱錯了,等等。
// initialize the data structures
var priorityQueue = new SortedDictionary<Record, Stream>();
var streams = new List<Stream>();
var outStream = null;
try
{
// open the streams.
outStream = OpenOutputStream();
foreach(var filename in filenames)
streams.Add(GetFileStream(filename));
// initialize the priority queue
foreach(var stream in streams)
{
var record = ReadRecord(stream);
if (record != null)
priorityQueue.Add(record, stream);
// the main loop
while(!priorityQueue.IsEmpty)
{
var record = priorityQueue.Smallest;
var smallestStream = priorityQueue[record];
WriteRecord(record, outStream);
priorityQueue.Remove(record);
var newRecord = ReadRecord(smallestStream);
if (newRecord != null)
priorityQueue.Add(newRecord, smallestStream);
}
}
finally { clean up the streams }
那有意義嗎? 您只需繼續從優先級隊列中抓取最小的東西,並將其替換為該流中的下一條記錄(如果有的話)。 最終隊列將為空,您將完成。
策略可能取決於數據量。
這是一個代碼示例,它讀入N個已排序的文本文件並合並它們。 我沒有包含重復檢查,但應該很容易實現。
首先是助手班。
class MergeFile : IEnumerator<string>
{
private readonly StreamReader _reader;
public MergeFile(string file)
{
_reader = File.OpenText(file);
Current = _reader.ReadLine();
}
public string Current { get; set; }
public void Dispose()
{
_reader.Close();
}
public bool MoveNext()
{
Current = _reader.ReadLine();
return Current != null;
}
public void Reset()
{
throw new NotImplementedException();
}
object IEnumerator.Current
{
get { return Current; }
}
}
然后編寫代碼進行讀取和合並(為了清晰起見,應該對其進行重構):
// Get the file names and instantiate our helper class
List<IEnumerator<string>> files = Directory.GetFiles(@"C:\temp\files", "*.txt").Select(file => new MergeFile(file)).Cast<IEnumerator<string>>().ToList();
List<string> result = new List<string>();
IEnumerator<string> next = null;
while (true)
{
bool done = true;
// loop over the helpers
foreach (var mergeFile in files)
{
done = false;
if (next == null || string.Compare(mergeFile.Current, next.Current) < 1)
{
next = mergeFile;
}
}
if (done) break;
result.Add(next.Current);
if (!next.MoveNext())
{
// file is exhausted, dispose and remove from list
next.Dispose();
files.Remove(next);
next = null;
}
}
我會說不要使用優先級隊列,不要使用IEnumerable。 兩者都很慢。
以下是在外部存儲器中對排序文件進行排序或合並的快速方法:
http://www.codeproject.com/KB/recipes/fast_external_sort.aspx
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.