例如,我从一些文件中检索了随机入口点和哈希
EP | Hash
25432|545676343
25732|344284432
93632|9432763432
45432|194363432
35433|345676325
15434|445676337
35439|745676343
55437|243276342
85532|476263821
85532|156743832
85532|626343633
85531|626343633
我们说清单非常庞大。
我希望将所有数据放入内存,因为它们只是Cardinal / Integer数据类型。
如果我想找到EP = 85532和Hash = 626343633,那么快速(est)方式是什么。我不认为for loop
就是答案。
注意:
感谢。
答案 0 :(得分:1)
据我所知,你在Delphi中没有哈希表。你当然可以轻松写一个,但你也可以只使用一个tDictonary
看看这个并看看它是否有意义:
procedure TForm1.FormCreate(Sender: TObject);
var
List: TDictionary<TPair<Integer, Cardinal>, Integer>;
begin
//Dummy data
List := TDictionary<TPair<Integer, Cardinal>, Integer>.Create;
List.Add(TPair<Integer, Cardinal>.Create(25432, 545676343), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(25732, 344284432), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(93632, 9432763432), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(45432, 194363432), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(35433, 345676325), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(15434, 445676337), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(35439, 745676343), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(55437, 243276342), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(85532, 476263821), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(85532, 156743832), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(85532, 626343633), List.Count);
List.Add(TPair<Integer, Cardinal>.Create(85531, 626343634), List.Count);
//check if exists
List.ContainsKey(TPair<Integer, Cardinal>.Create(85531, 626343634));
//Free data
FreeAndNil(List);
end;
答案 1 :(得分:1)
这是一个包含字典和对象的示例,如果需要,它可以存储和构建哈希值。
program so_28337613;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Generics.Collections,
System.Generics.Defaults;
type
// data object
THasher = class
private
FEP: Integer;
FHasHash: Boolean;
FHash: Cardinal;
function GetHash: Cardinal;
protected
procedure BuildHash( out AHash: Cardinal );
public
constructor Create( const EP: Integer ); overload;
constructor Create( const EP: Integer; const Hash: Cardinal ); overload;
property EP: Integer read FEP;
property Hash: Cardinal read GetHash;
end;
{ THasher }
procedure THasher.BuildHash( out AHash: Cardinal );
begin
Writeln( 'DEBUG: Building Hash' );
AHash := FEP;
end;
constructor THasher.Create( const EP: Integer );
begin
inherited Create;
FEP := EP;
end;
constructor THasher.Create( const EP: Integer; const Hash: Cardinal );
begin
Create( EP );
FHash := Hash;
FHasHash := True;
end;
function THasher.GetHash: Cardinal;
begin
if not FHasHash
then
begin
BuildHash( FHash );
FHasHash := True;
end;
Result := FHash;
end;
procedure Test;
var
LHashDict: TObjectDictionary<THasher, Boolean>;
LSearchFor: THasher;
begin
LSearchFor := nil;
LHashDict := nil;
try
LHashDict := TObjectDictionary<THasher, Boolean>.Create(
{Ownerships} [doOwnsKeys],
{AEqualityComparer} TEqualityComparer<THasher>.Construct(
{EqualityComparison} (
function( const L, R: THasher ): Boolean
begin
Writeln( 'DEBUG: Compare' );
Result := ( L.EP = R.EP ) and ( L.Hash = R.Hash );
end ),
{Hasher} (
function( const I: THasher ): Integer
begin
Result := I.EP;
end ) ) );
// Add known hashes
LHashDict.Add( THasher.Create( 1, 45 ), True );
LHashDict.Add( THasher.Create( 2, 56 ), True );
LHashDict.Add( THasher.Create( 3, 76 ), True );
LHashDict.Add( THasher.Create( 4, 34 ), True );
LHashDict.Add( THasher.Create( 5, 5 ), True );
LHashDict.Add( THasher.Create( 6, 23 ), True );
LHashDict.Add( THasher.Create( 7, 78 ), True );
LHashDict.Add( THasher.Create( 8, 89 ), True );
// Looking for an object with now unknown hash
LSearchFor := THasher.Create( 5 );
if LHashDict.ContainsKey( LSearchFor )
then
Writeln( 'GOTCHA' );
finally
LHashDict.Free;
end;
end;
begin
try
Test;
except
on E: Exception do
Writeln( E.ClassName, ': ', E.Message );
end;
Readln;
end.
当调试输出状态时,只有一个比较和一个哈希构建。
答案 2 :(得分:0)
除非您的数据具有比当前可观察的结构更多的结构(它似乎是无序的),并且您希望仅执行一次查找,否则您将无法击败线性搜索,即使它具有O( n)复杂性。所有其他选项至少具有第一次搜索的复杂性。
如果订购了数据,那么您可以使用二进制搜索有效地搜索多个项目。如果数据没有被订购,那么它是一个O(n log n)操作来订购它,这显然是昂贵的。但是,一旦订购,则二进制搜索为O(log n)。
另一种选择是填充字典。标准的Delphi字典有O(1)查找。然而,再次形成字典是昂贵的。但是如果你可以在排序和构建字典之间做出选择,那就选择后者,因为它应该更快地构建和执行查找。
总结:
从表面上看,人们会认为EP是你词典的关键。但是你似乎有多对具有相同的EP。所以我猜你需要一个复杂的价值结构,其中包含与一个特定EP密钥相关的所有信息。
答案 3 :(得分:0)
虽然我的下一个建议不会为您提供最佳性能,但它很容易实现,并且仍能提供相当好的性能。
现在,在数据搜索中获得性能的最简单方法是将数据拆分为有组织的组。
根据您声称主搜索键是EP值并且EP值似乎是五位数的事实,我建议创建100个组(单独的数组)。
这些数组中的每一个都会以这样的方式存储部分数据:
首先排列EP值介于0和1000之间的所有项目
第二个数组所有EP值在1001和2000之间的项目
...
这将允许使用启发式方法来减少您需要迭代的项目数量,只需要确定特定项目属于哪个组,然后只迭代该特定组中的项目。您只需将EP值除以1000就可以做到这一点。
这大大减少了您需要迭代的项目数量,并且不要求您按照二进制搜索的要求对所有项目进行完美排序。
此外,如果可能存在大量具有相同EP值的不同项目,您可能需要创建单独的数组来存储具有相同EP值的多个项目,以减少内存使用量。
因此,例如,具有用于存储的单独数组让我们说100个具有EP值25759的项目将仅需要32位用于对阵列的引用以及100倍32位(整数的大小),其总计3232位或404字节。登记/> 但是将这些项目成对存储将需要基本部分的32位32位和整数部分的32位,总计为6400位或800字节。
答案 4 :(得分:0)
假设您可以为您需要的数据项目中添加一个数字,那么这可能是一种方法。我无法想象检索可能会更快但这是以记忆为代价的......
unit EZStore;
interface
const
MAX_HASHES = 5;
MAX_EPS = 10000000;
type
THashArray = Array[0..MAX_HASHES -1] of Int64;
TEZStore = class(TObject)
private
FData : Array[0..MAX_EPS - 1] of THashArray;
public
procedure Initialise();
procedure Store(const AEP : Integer; const AHash : Int64);
function Retrieve(const AEP : Integer) : THashArray;
end;
implementation
uses
SysUtils;
procedure TEZStore.Initialise;
begin
FillChar(FData, MAX_HASHES * MAX_EPS, 0);
end;
function TEZStore.Retrieve(const AEP: Integer): THashArray;
begin
Result := FData[AEP];
end;
procedure TEZStore.Store(const AEP: Integer; const AHash: Int64);
var
ThisHashArray : THashArray;
i : integer;
begin
i := 0;
ThisHashArray := FData[AEP];
while(FData[AEP][i] <> 0) do begin
Inc(i);
if (i > MAX_HASHES - 1) then
raise Exception.Create(Format('The maximum of %d hashes per entry point has been exceeded', [MAX_HASHES]));
end;
FData[AEP][i] := AHash;
end;
end.