2009-10-21 88 views
3

我有一个10000条目的字符串列表。我有一个洗牌程序,但访问任何项目都花费了很多时间。通过所有10K项目需要大量的时间。随机文本文件德尔福来源或其他

我想保存它做的磁盘,然后使用另一种方法对文件进行洗牌。

有什么建议吗?

回答

7

您的洗牌程序如何实施?特别是交换程序?如果你已经写下你自己的,请按照以下方式:

vTempSrting := vStringList[I]; 
vStringList.Delete(I); 
vStringList.Insert(J,vTempString); 

它会很慢。在字符串列表上使用交换方法。

此代码了78毫秒我非常平均(3岁)计算机:

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils,Classes,uIntegerList,Windows,Math; 

procedure Shuffle(aSL : TStringList); 
var I,J : integer; 
begin 
    for I := 0 to aSL.Count-1 do 
    begin 
    J := randomrange(I,aSL.Count); 
    aSL.Exchange(I,J); 
    end; 
end; 

procedure CreateTestFile; 
var 
    vSL : TStringList; 
    I : integer; 
begin 
    vSL := TStringList.Create; 
    try 
    for I := 1 to 100000 do vSL.Add('Sample text #'+inttostr(I)); 
    vSL.SaveToFile('c:\test.txt'); 
    finally 
    vSL.Free; 
    end; 
end; 

function TestShuffle : longword; 
var 
    vSL : TStringList; 
    vTick0 : longword; 
begin 
    vSL := TStringList.Create; 
    try 
    vTick0 := gettickcount; 
    vSL.LoadFromFile('c:\test.txt'); 
    Shuffle(vSL); 
    vSL.SaveToFile('c:\test.txt'); 
    Result := gettickcount - vTick0; 
    finally 
    vSL.Free; 
    end; 
end; 

begin 
    CreateTestFile; 
    writeln(TestShuffle,' ms'); 
    readln; 
end. 
+0

哇感谢代码svein! 我确实使用了交换,但我刚刚解决了我的问题 - 字符串从备忘录传递到了我的shuffeling过程 - 显然,每次更新后,备忘录必须更新10000个视觉项目! 我现在使用中介AstrinList,对其进行排序,然后将其分配回备忘录: aStringLIst:= TStringList.Create; aStringList.Assign(mNumbers.Lines); Shuffle(aStringList); mNumbers.Lines.Assign(aStringList); aStringList.Free; 这是瞬间! 非常感谢 – 2009-10-21 11:45:04

+0

哇的评论真的搞砸了我的代码,抱歉希望你能把它弄出来。 – 2009-10-21 11:46:13

+0

没问题,我可以读它:-) – 2009-10-21 11:47:08

1

在内存中重新排列字符串列表很慢,所以我会将索引列表作为初始优化进行洗牌。

我猜你选择了stringlist方便从磁盘加载和保存到磁盘。一个更快的方法是洗牌索引。创建一个由10,000个整数组成的数组,然后使用临时字符串变量来保存交换元素,并使用混洗后的索引值从上到下重新排列字符串列表。

主要重写将提供更大的改进,但这可能有助于如果你的字符串不是太大。

+0

我确实使用TStringList,但问题是访问任何东西需要很长时间,所以只需从上到下扫描需要几分钟。 这只是一个数字列表,所以我可以将它加载到数组中并随机播放它。 我喜欢TStringList功能,但是,有没有索引TStringList或者什么? – 2009-10-21 11:07:36

1

一个简单的方法是生成随机数的列表,排序,然后做数据的两两互换后。排序可以作为o(n * log(n))算法完成,而交换总是一个o(n)算法,因此速度要快得多。

为防万一您没有想到它,请考虑将数据保持原样,并保存一个额外的洗牌索引。

1

我在创建混洗范围之前问过一个问题 - 而不是生成一个数字列表然后洗牌,我想要一个函数能够迭代地返回混洗数字列表,而不需要O(n)内存费用:

Generating shuffled range using a PRNG rather than shuffling

如果创建某种指数,为您在磁盘上的文件,那么你就可以不用管内存成本,这对于非常大的文件创建重要的一个改组型式。对于索引,我建议一些简单的东西,比如每行开始的位置(32或64位整数)。这样,为了从文本文件中提取出第N行,可以简单地在索引流中查找N * 4(或64 *索引的N * 8)以发现行开始的偏移量,然后尝试在文本文件流中的位置并读出一行。

使用此方法,您可以洗牌超大文件,而无需支付内存中的成本。当然,混洗意味着从源文件中随机提取行,除非文件非常小(适合缓存几乎在第一次访问时)或非常大(在这种情况下,内存抖动会比随机搜索更糟糕),或者如果你没有使用机械硬盘驱动器(例如SSD)。

对于你的情况,10K真的不是一个大数字。在1000万行的区域中,可能会占用几千兆字节的文本(当然取决于行长度),将会变得更具挑战性,这就是32位的这种方法(或类似方法)所必需的。

+0

感谢Barry,尽管我发现我的错误是使用shuffle函数进行控件的视觉更新。虽然有趣的方法! – 2009-10-23 11:05:21