大悟还俗

邮箱 key_ok@qq.com 我的收集 http://pan.baidu.com/share/home?uk=1177427271
posts - 236, comments - 8, trackbacks - 0, articles - 0
  新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

Delphi中的THashTable

Posted on 2013-10-09 12:05 大悟还俗 阅读(...) 评论(...) 编辑 收藏

在Delphi中,Inifiles单元中有一个TStringHash的类,不过它的Value仅支持Integer(其实也不是问题,有其它类型可以将变量变为Pointer),有点不舒服,今天没事做就把它替换为variant了,其中Key的名称大小写无关,就是为了加快开发速度!

使用Hashtable,查找和删除复杂度都是常数级别的!

type
  PPHashItem = ^PHashItem;
  PHashItem = ^THashItem;
  THashItem = record
    Next: PHashItem;
    Key: String;
    Value: Variant;
  end;
  THashTable = class
  private
    Buckets: array of PHashItem;
  protected
    function Find(const Key: String): PPHashItem;
    function HashOf(const Key: String): Cardinal; virtual;
  public
    constructor Create(Size: Cardinal = 256);
    destructor Destroy; override;
    procedure Put(const Key: String; Value: Variant);
    procedure Clear;
    procedure Remove(const Key: String);
    function Modify(const Key: String; Value: Variant): Boolean;
    function Get(const Key: String): Variant;
    function ContainKey(const Key: String):boolean;
  end;
procedure THashTable.Clear;
var
  I: Integer;
  P, N: PHashItem;
begin
  for I := 0 to Length(Buckets) - 1 do
  begin
    P := Buckets[I];
    while P <> nil do
    begin
      N := P^.Next;
      Dispose(P);
      P := N;
    end;
    Buckets[I] := nil;
  end;
end;
function THashTable.ContainKey(const Key: String): boolean;
var
  P: PHashItem;
begin
  P := Find(Key)^;
  if P <> nil then
  begin
    Result := True;
  end
  else
    Result := False;
end;
constructor THashTable.Create(Size: Cardinal);
begin
  inherited Create;
  SetLength(Buckets, Size);
end;
destructor THashTable.Destroy;
begin
  Clear;
  inherited Destroy;
end;
function THashTable.Find(const Key: String): PPHashItem;
var
  Hash: Integer;
begin
  Hash := HashOf(Key) mod Cardinal(Length(Buckets));
  Result := @Buckets[Hash];
  while Result^ <> nil do
  begin
    if Result^.Key = Key then
      Exit
    else
      Result := @Result^.Next;
  end;
end;
function THashTable.Get(const Key: String): Variant;
var
  P: PHashItem;
begin
  P := Find(AnsiUpperCase(Key))^;
  if P <> nil then
    Result := P^.Value
  else
    Result := -1;
end;
function THashTable.HashOf(const Key: String): Cardinal;
var
  I: Integer;
begin
  Result := 0;
  for I := 1 to Length(Key) do
    Result := ((Result shl 2) or (Result shr (SizeOf(Result) * 8 - 2))) xor
      Ord(Key[I]);
end;
function THashTable.Modify(const Key: String; Value: Variant): Boolean;
var
  P: PHashItem;
begin
  P := Find(Key)^;
  if P <> nil then
  begin
    Result := True;
    P^.Value := Value;
  end
  else
    Result := False;
end;
procedure THashTable.Put(const Key: String; Value: Variant);
var
  Hash: Integer;
  Bucket: PHashItem;
begin
  Hash := HashOf(AnsiUpperCase(Key)) mod Cardinal(Length(Buckets));
  New(Bucket);
  Bucket^.Key := AnsiUpperCase(Key);
  Bucket^.Value := Value;
  Bucket^.Next := Buckets[Hash];
  Buckets[Hash] := Bucket;
end;
procedure THashTable.Remove(const Key: String);
var
  P: PHashItem;
  Prev: PPHashItem;
begin
  Prev := Find(Key);
  P := Prev^;
  if P <> nil then
  begin
    Prev^ := P^.Next;
    Dispose(P);
  end;
end;
View Code
使用












var
  Demo:THashTable;
begin
  Demo:=THashTable.Create();
  try
    Demo.Put('id',1);
    ShowMessage(Demo.Get('id'));
  finally
    Demo.Free;
  end;
end;
View Code