根据VCL的TStringHash写的哈希表类。
unit zjHashedTable;
interface
uses
SysUtils,
Classes;
type
TzjStringHashProc = function(const aKey:string):Cardinal;
TzjHashItemDisposeProc = procedure(aData
ointer);
TzjHashTableIterator = function(aKey:string;aData
ointer;aParam:LongInt):Boolean;
PPzjHashItem = ^PzjHashItem;
PzjHashItem = ^TzjHashItem;
TzjHashItem = record
Next: PzjHashItem;
Key: string;
Data: Pointer;
end;
TzjHashedTable = class(TObject)
private
Buckets: array of PzjHashItem;
FHashProc: TzjStringHashProc;
FDisposeProc:TzjHashItemDisposeProc;
FOwnsItem:Boolean;
FCount:Integer;
function GetContents: TList;
function GetCapacity: Integer;
public
constructor Create(aHashProc:TzjStringHashProc = nil;aSize: Cardinal = 256);
destructor Destroy; override;
function Find(const aKey: string;aPos: Integer = -1): PzjHashItem;
function Insert(const aKey: string; aData: Pointer; FailIfExists:Boolean = False):Boolean;
procedure Clear;
function Remove(const aKey: string):Boolean;
function Extract(const aKey: string;out aData
ointer):Boolean;
function Modify(const aKey: string; aData: Pointer): Boolean;
function GetItem(const aKey: string;out aData
ointer): Boolean;
function Exists(const aKey:string):Boolean;
function Iterate(aIteratePrco:TzjHashTableIterator;aParam:LongInt):Boolean;
property Contents:TList read GetContents;
property DisposeProc:TzjHashItemDisposeProc read FDisposeProc write FDisposeProc;
property OwnsItem:Boolean read FOwnsItem write FOwnsItem;
property Count:Integer read FCount;
property Capacity:Integer read GetCapacity;
end;
implementation
function DefStringHash(const aKey:string):Cardinal;
var
I: Integer;
begin
Result := 0;
for I := 1 to Length(aKey) do
Result := ((Result shl 2) or (Result shr (SizeOf(Result) * 8 - 2))) xor
Ord(aKey
);
end;
{ TzjHashedTable }
procedure TzjHashedTable.Clear;
var
I: Integer;
P, N: PzjHashItem;
begin
for I := 0 to Length(Buckets) - 1 do
begin
P := Buckets;
while P <> nil do
begin
N := P^.Next;
if Self.FOwnsItem then
Self.FDisposeProc(P.Data);
Dispose(P);
P := N;
end;
end;
FillChar(Buckets[0],Length(Buckets)*SizeOf(PzjHashItem),0);
FCount:=0;
end;
constructor TzjHashedTable.Create(aHashProc:TzjStringHashProc;aSize: Cardinal);
begin
if @aHashProc=nil then
Self.FHashProc:=@DefStringHash
else
Self.FHashProc:=@aHashProc;
SetLength(Buckets, aSize);
FillChar(Buckets[0],Length(Buckets)*SizeOf(PzjHashItem),0);
FCount:=0;
end;
destructor TzjHashedTable.Destroy;
begin
Clear;
inherited;
end;
function TzjHashedTable.Exists(const aKey: string): Boolean;
begin
Result:=Find(aKey)<>nil;
end;
function TzjHashedTable.Extract(const aKey: string;out aData: Pointer): Boolean;
var
Hash: Integer;
P,PrevzjHashItem;
begin
Result:=False;
Hash := FHashProc(aKey) mod Cardinal(Length(Buckets));
Prev:=nil;
P := Buckets[Hash];
while P <> nil do
begin
if P.Key = aKey then
begin
if Prev<>nil then
Prev.Next:=P.Next
else
Buckets[Hash]:=P.Next;
aData:=P.Data;
Dispose(P);
Dec(FCount);
Result:=True;
Break;
end
else
begin
Prev:=P;
P:=P.Next;
end;
end;
end;
function TzjHashedTable.Find(const aKey: string;aPos: Integer): PzjHashItem;
var
Hash: Integer;
begin
if aPos < 0 then
Hash := FHashProc(aKey) mod Cardinal(Length(Buckets))
else
Hash := aPos;
Result := Buckets[Hash];
while Result <> nil do
begin
if Result.Key = aKey then
Exit
else
Result := Result.Next;
end;
end;
function TzjHashedTable.GetCapacity: Integer;
begin
Result:=Length(Buckets);
end;
function TzjHashedTable.GetContents: TList;
var
I,J: Integer;
P: PzjHashItem;
begin
if FCount=0 then
begin
Result:=nil;
Exit;
end;
Result:=TList.Create;
Result.Count:=Self.FCount;
J:=0;
for I := 0 to Length(Buckets) - 1 do
begin
P := Buckets;
while P <> nil do
begin
Result.Items[J]:=P.Data;
Inc(J);
P:=P.Next;
end;
end;
end;
function TzjHashedTable.GetItem(const aKey: string;out aData: Pointer): Boolean;
var
P: PzjHashItem;
begin
P := Find(aKey);
if P=nil then
Result:=False
else
begin
aData:=P.Data;
Result:=True;
end;
end;
function TzjHashedTable.Insert(const aKey: string; aData: Pointer; FailIfExists:Boolean):Boolean;
var
Hash: Integer;
P,Bucket: PzjHashItem;
begin
Result:=False;
Hash := FHashProc(aKey) mod Cardinal(Length(Buckets));
P:=Self.Find(aKey,Hash);
if p=nil then
begin
New(Bucket);
Bucket.Key := aKey;
Bucket.Data := aData;
Bucket.Next := Buckets[Hash];
Buckets[Hash] := Bucket;
Inc(FCount);
Result:=True;
end
else if not FailIfExists then
begin
if Self.FOwnsItem then
Self.FDisposeProc(P.Data);
P.Data:=aData;
Inc(FCount);
Result:=True;
end;
end;
function TzjHashedTable.Iterate(aIteratePrco: TzjHashTableIterator;
aParam: Integer): Boolean;
var
I: Integer;
P: PzjHashItem;
begin
Result:=False;
for I := 0 to Length(Buckets) - 1 do
begin
P := Buckets;
while P <> nil do
begin
Result:=aIteratePrco(P.Key,P.Data,aParam);
if Result then Exit;
P:=P.Next;
end;
end;
end;
function TzjHashedTable.Modify(const aKey: string;aData: Pointer): Boolean;
var
P: PzjHashItem;
begin
P := Find(aKey);
if P = nil then
Result:=False
else
begin
if P.Data<>aData then
begin
if Self.FOwnsItem then
Self.FDisposeProc(P.Data);
P.Data:=aData;
Result:=True;
end
else
Result:=False;
end;
end;
function TzjHashedTable.Remove(const aKey: string): Boolean;
var
Pointer;
begin
Result:=Self.Extract(aKey,P);
if Result and Self.FOwnsItem then
Self.FDisposeProc(P);
end;
end.