Delphi中的哈希?

曾經看到很多人在嚷嚷Delphi沒有哈希表,這些人的動手意識姑且不論,卻還有很多人以此來證明Delphi比別的語言垃圾,實在是...

好,牢騷打住,轉接正題。

TStringList是我們常用的字符串列表類型,用法就不在這裏贅述,但是,在數據其項數增多時,其搜索(主要是name/key搜索和indexof搜索)性能會急劇下降,原因是TStringList的內部存儲使用了鏈表形式,而搜索操作使用了循環遍歷方式。

值得高興的是,在iniFiles單元,Delphi爲我們提供了THashedStringList類型,即,經過哈希處理的TStringList,它繼承自TStringList,只是對搜索方法進行了優化,因此,我們完全可以放心的在大量字符串搜索的時候使用它來代替TStringList,而需要改變的只是在:=的後面用THashedStringList.create來代替TStringList.create,但其速度卻提高了一個數量級。

爲了顯示兩者間性能的差距,我寫了幾個簡單的語句來測試他們各自的特性。

 

unit ufrmMainForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrUtils,IniFiles;

type
  TForm1 
= class(TForm)
    btn1: TButton;
    mmo1: TMemo;
    procedure btn1Click(Sender: TObject);
  
private
    
{ Private declarations }
  
public
    procedure testTHashStringList;
    procedure testTStringList;
    
{ Public declarations }
  end;

var
  Form1: TForm1;

implementation
uses DateUtils;

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
begin
    testTStringList;
    mmo1.Lines.Add(
'--------------------');
    testTHashStringList;
end;

procedure TForm1.testTHashStringList;
var
    hsl: THashedStringList;
  I: Integer;
  datePointer: TDateTime;
  hslTime, hslTimeC, hslTimeI: Int64;
  tempInt: Integer;
  tempstr: 
string ;
begin

    hslTime := 0;
    hslTimeC :
= 0;
    datePointer :
= Now();
    hsl :
= THashedStringList.Create();

    
for I := 1 to 200000 do
    begin
        hsl.Add(
'string_'+IntToStr(i));
    end;
    hslTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'200000 項 THashedStringList 創建耗時:'+IntToStr(hslTime)+'毫秒');

    datePointer :
= Now();
    
for I := 0 to 200 do
    begin
        tempInt :
= hsl.IndexOf('string_'+IntToStr(i*1000));
    end;
    hslTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'200 項字符串搜索 THashedStringList 耗時:'+IntToStr(hslTime)+'毫秒');

    datePointer :
= Now;
    
for I := 1 to 200000 do
    begin
        tempstr :
= hsl.Strings[i -1];
    end;
    hslTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'200000 項索引搜索 THashedStringList 耗時:'+IntToStr(hslTime)+'毫秒');
    hsl.Clear;

    datePointer :
= Now;
    
for I := 1 to 100000 do
    begin
        hsl.Insert(i
-1'string_'+IntToStr(i));
    end;
    hslTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'100000 項 THashedStringList 隨位置插入耗時:'+IntToStr(hslTime)+'毫秒');

    datePointer :
= Now;
    
for I := 1 to 100000 do
    begin
        hsl.Insert(
0'string_'+IntToStr(i));
    end;
    hslTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'100000 項 THashedStringList 0位置插入耗時:'+IntToStr(hslTime)+'毫秒');

end;

procedure TForm1.testTStringList;
var
    sl: TStringList;
  I: Integer;
  datePointer: TDateTime;
  slTime, slTimeC, slTimeI: Int64;
  tempInt: Integer;
  tempstr: 
string ;
begin

    slTime := 0;
    slTimeC :
= 0;
    datePointer :
= Now();
    sl :
= TStringList.Create;
    
for I := 1 to 200000 do
    begin
        sl.Add(
'string_'+IntToStr(i));
    end;
    slTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'200000 項 TStringList 創建耗時:'+IntToStr(slTime)+'毫秒');

    datePointer :
= Now;
    
for I := 0 to 200 do
    begin
        tempInt :
= sl.IndexOf('string_'+IntToStr(i*1000));
    end;
    slTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'200 項字符串搜索 TStringList 耗時:'+IntToStr(slTime)+'毫秒');

    datePointer :
= Now;
    
for I := 1 to 200000 do
    begin
        tempstr :
= sl.Strings[i -1];
    end;
    slTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'200000 項索引搜索 TStringList 耗時:'+IntToStr(slTime)+'毫秒');
    
    datePointer :
= Now;
    
for I := 1 to 100000 do
    begin
        sl.Insert(i
-1,'string_'+IntToStr(i));
    end;

    slTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'100000 項 TStringList 隨位置插入耗時:'+IntToStr(slTime)+'毫秒');

    datePointer :
= Now;
    
for I := 1 to 100000 do
    begin
        sl.Insert(
0,'string_'+IntToStr(i));
    end;

    slTime :
= MilliSecondsBetween(Now, datePointer);
    mmo1.Lines.Add(
'100000 項 TStringList 0位置插入耗時:'+IntToStr(slTime)+'毫秒');

end;

end.

編譯運行程序,其運行結果:

200000 項 TStringList 創建耗時:109毫秒
200 項字符串搜索 TStringList 耗時:11514毫秒
200000 項索引搜索 TStringList 耗時:31毫秒
100000 項 TStringList 隨位置插入耗時:85828毫秒
100000 項 TStringList 0位置插入耗時:148734毫秒
--------------------
200000 項 THashedStringList 創建耗時:108毫秒
200 項字符串搜索 THashedStringList 耗時:188毫秒
200000 項索引搜索 THashedStringList 耗時:15毫秒
100000 項 THashedStringList 隨位置插入耗時:63毫秒
100000 項 THashedStringList 0位置插入耗時:55640毫秒

(測試環境:Windows2003  SP1  +Delphi 2006 Update 2 HotFix1-9 +1G內存 +P-D2.8G雙核)

結果很明顯,兩者在創建的時候,性能並沒有差距(之前聽人說THashedStringList在增加和插入操作時會比 TStringList慢,在此並沒有顯示出來,不知道是不是因爲THashedStringList並不是人們說的那樣,在每次插入項時都做哈希操作,還請各位不吝賜教),而200 項字符串搜索(從1到2000000項勻距搜索200項)中,兩者的性能竟差如此懸殊。其後的各項測試也在預料之中。

由此可見,THashedStringList能更好的代替我們常用的TStringList來工作,我們爲什麼要拒絕呢?

另外,iniFiles單元還提供了TStringHash,但只是對key進行了哈希操作,一般不常用。  

發佈了14 篇原創文章 · 獲贊 3 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章