I am working on a project that requires me to store and later validate/search for a set of pointers, and I could use a hand with the hash function for calculating the index.
First, the requirements:
1.) I only need comments/assistance with the hash function itself, nothing else. Do not suggest things like sorted lists, binary trees, etc.
2.) My hash table size needs to be kept in the ballpark of 16384 items; I will be using bucket chaining for collisions resolution. The 16384 is designed to be optimal with the storage of appx 256K items (a perfect distribution will mean a maximum of 16 checks per lookup, vs the 18 max checks required by a binary search)
3.) The keys for the hash are memory pointers, and more specifically, will come from either a GetMem or AllocMem call. This does give them (the keys) some traits, such as being 4 byte aligned, etc.
4.) 500 pts will be given to each answer that is an improvement on what I already have.
Here is the test frame work that I currently have set up. Again, I am only looking for enhancements to the following function.
function TForm1.HashIndex(Value: Pointer): Integer;
Thanks to all in advance,
Russell
--- Form Source Code ---
unit main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
// Prime number for hash size
const
HASH_SIZE = 16349;
// Hash definition
type
THashArray = Array [0..Pred(HASH_SIZE)] of Integer;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
private
// Private declarations
FMaxCount: Integer;
FHashArray: THashArray;
public
// Public declarations
function HashIndex(Value: Pointer): Integer;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function TForm1.HashIndex(Value: Pointer): Integer;
var Key: Integer;
begin
// Mod the value with the hash size
result:=(Integer(Value) shr 6) mod HASH_SIZE;
end;
procedure TForm1.Button1Click(Sender
: TObject);
var List: TList;
i: Integer;
j: Integer;
p: Pointer;
dwStats: Array [0..2] of Integer;
dwSlots: Integer;
arrInts: Array of Integer;
begin
// Setup for test
List:=TList.Create;
ListBox1.Items.Clear;
ZeroMemory(@FHashArray, SizeOf(THashArray));
Randomize;
try
// Allocate memory blocks and increment the hash slot of where the item falls
for i:=0 to 262144 do
begin
p:=AllocMem(Succ(Random(32
)));
Inc(FHashArray[HashIndex(p
)]);
List.Add(p);
end;
// Calculate the hash stats
dwStats[0]:=0; // Max value
dwStats[1]:=MaxInt; // Min value
dwStats[2]:=0; // Count of empty slots
for i:=0 to High(FHashArray) do
begin
if (FHashArray[i] > dwStats[0]) then dwStats[0]:=FHashArray[i];
if (FHashArray[i] < dwStats[1]) then dwStats[1]:=FHashArray[i];
if (FHashArray[i] = 0) then Inc(dwStats[2]);
end;
// Allocate memory for the number of slots
dwSlots:=Succ(dwStats[0]-d
wStats[1])
;
SetLength(arrInts, dwSlots);
// Fill in the count for each slot
for i:=dwStats[1] to dwStats[0] do
begin
for j:=0 to High(FHashArray) do
begin
if (FHashArray[j] = i) then Inc(arrInts[i-dwStats[1]])
;
end;
end;
// Graph the hash statistics
ListBox1.Items.BeginUpdate
;
FMaxCount:=0;
for i:=dwStats[1] to dwStats[0] do
begin
j:=arrInts[i-dwStats[1]];
if (j > FMaxCount) then FMaxCount:=j;
ListBox1.Items.AddObject(F
ormat('%d bucket(s) with %d items', [j, i]), Ptr(j));
end;
ListBox1.Items.EndUpdate;
Caption:=Format('Min bucket count = %d, Max bucket count = %d', [dwStats[1], dwStats[0]]);
// Free memory
SetLength(arrInts, 0);
finally
// Free test memory
for i:=Pred(List.Count) downto 0 do FreeMem(List[i]);
// Tear down test
List.Clear;
List.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FMaxCount:=0;
end;
procedure TForm1.ListBox1DrawItem(Co
ntrol: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
var dwCount: Integer;
rcFill: TRect;
dblPct: Double;
begin
// Calculate the percentage based on max and count
dwCount:=Integer(ListBox1.
Items.Obje
cts[Index]
);
dblPct:=(dwCount / Succ(FMaxCount));
// Get the rect to draw
with ListBox1.Canvas do
begin
FillRect(Rect);
rcFill:=Rect;
rcFill.Right:=rcFill.Left+
Trunc((rcF
ill.Right-
rcFill.Lef
t) * dblPct);
Brush.Color:=clYellow;
FillRect(rcFill);
Brush.Color:=clWindow;
SetBkMode(Handle, TRANSPARENT);
TextOut(Rect.Left+2, Rect.Top+2, ListBox1.Items[Index]);
end;
end;
end.
--- form ---
object Form1: TForm1
Left = 80
Top = 117
Width = 638
Height = 373
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 8
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object ListBox1: TListBox
Left = 136
Top = 0
Width = 494
Height = 339
Align = alRight
ItemHeight = 16
Style = lbOwnerDrawFixed
TabOrder = 1
OnDrawItem = ListBox1DrawItem
end
end