![]() |
AW: Hashtable, wie benutzen?
Zitat:
Sofern die Daten nicht sortiert vorliegen, sollte das Ausschließen doppelter Einträge über eine Hashmap am Schnellsten sein. Das Suchen eines Elements in einer Hashmap ist vom Aufwand O(1), das binäre Suchen dagegen O(log n). Die Hashfunktion einer 64-bit Zahl lässt sich auf N mod <HashMapSize> kürzen. Ich schaffe hier 1 Mio Tests in 370ms. Das wäre ja auszuhalten. |
AW: Hashtable, wie benutzen?
Hallo,
Binsuche dauert zwar "nur" etwa 4xmal so lang auf meinem 2,3 Ghz Notebook bei 1 Mio Elementen, aber das Aufrechterhalten der Sortierung kostet viel zuviel Zeit. Gruß Horst |
AW: Hashtable, wie benutzen?
Zitat:
- Der Pointer kriegt einfach immer NIL übergeben? - Brauch ich das Array "Samples[]" auch, oder übernimmt das Dictionary beide Datenfelder? Nehmen wir mal ich habe einen fortlaufenden Integer 0..5Millionen jeweils eine zugehörige Zufallszahl vom Typ INT64 und die INT64 möchte ich auf Gleichheit/Kollision überprüfen und dann den zugehörigen Integer wissen. Was übergebe ich dann dem Dictionary? Nur Mydict.add(INT64, nil)? Und den zugehörigen Integer muss ich mir dann im Array suchen? Oder kann ich Integer UND Int64 im MyDict speichern? Danke!:thumb: |
AW: Hashtable, wie benutzen?
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe jetzt keine Version von csDictionary gesehen, die mit Int64 umgeht, sondern nur cardinal. Deshalb habe ich dort einen TDictIntType eingeführt und dann auf Int64 zugewiesen. Die procedure Add habe ich in eine Function:boolean umgewandelt, damit ich weiß, ob der Wert eingefügt wurde, also schon vorhanden war, sonst hätte ich .contains nutzen müssen, was in .Add ja auch gemacht wird. Das sollte ich vielleicht alzaimar ( wo ist der überhaupt ? ) vorschlagen. Ich habe statt eines Pointers auf den Schlüssel A64[j] den Index j im Feld A64 im Hashfeld abgespeichert. 10 Mio Werte sind in 7,6 Sekunden eingefügt.( 420 MB belegt )
Delphi-Quellcode:
Anhand des Schlüssels erhält man also die Position im Feld.
A64 : array of TDictIntType;//Int64
j := low(A64); For i := low(A64) to High(A64) do begin Wert := random(RANDOMRANGE); // Nur wenn der Wert nicht doppelt war // wird er eingefuegt IF TestHash.Add(Wert,Pointer(j)) then begin A64[j] := Wert; inc(j); end; end; setlength(A64,j); Die Ausgabe auf dem Notebook ist dann:
Code:
25e6 Werte brauchen über 1 Gbyte
Erzeugen von 10000000 Zufallszahlen [0..9223372036854775806] 00:00:00,678
Einfügen von 10000000 verschiedenen Daten in 00:00:07,546 0 702565670347126292 TRUE 0 1 8731026331172931038 TRUE 1 2 7315597276161830344 TRUE 2 3 6054991081758643474 TRUE 3 4 974630338373080205 TRUE 4 5 2802662720263935392 TRUE 5 6 992661471859547074 TRUE 6 7 7770774513438344891 TRUE 7 8 2847780276242346111 TRUE 8 9 8442204931085970693 TRUE 9 10 2662600269196791808 TRUE 10 Auflösen der Hashmap in 00:00:04,574 Ich hoffe den Index abzuspeichern macht Sinn für Dich Gruß Horst P.S In einer Hash-Tabelle kann es keine doppelten Einträge geben. Edit: ich habe create geändert, sodass man man die zu erwartende Anzahl der Elemente vorgeben kann, das beschleunigt auf dem Desktop Rechner die Einfüge Zeit von 15,5 auf 7,6 Sekunden, der Abbau dauert 8,4 Sekunden. |
AW: Hashtable, wie benutzen?
Danke, habs jetzt unter Delphi 2009, Win7 zum laufen gebracht. Allerdings knallt es regelmässig nach ca. 500 bis 2000 Schleifendurchläufen und zwar beim
Delphi-Quellcode:
Wohl bei der ersten Kollision?! Warum versteh ich noch nicht ganz...
Hash.Add:
-> Zeile 535 der DictionaryUnit With PIntHashEntry(Result)^ Do If heKey = aKey Then <-- hier knallts Exit Verstehe ich deinen Programmablauf richtig, dass die Hashmap verhindert, dass ein schon vorhandener Wert ins Array kommt? PS: QWord kennt mein Delphi nicht. Habs durch INT64 ersetzt. |
AW: Hashtable, wie benutzen?
Kann ich nicht nachvollziehen (D2007).
|
AW: Hashtable, wie benutzen?
Hallo,
ich bekomme den Fehler auch nicht hin :-( Ich habe mal DictFind.pas geändert. Es wird jetzt eine lineare Liste erzwungen.
Delphi-Quellcode:
denn alle erzeugten Zahlen Wert sind verschieden, aber (Wert mod ccInitialSize) = 17.
function myRandom(i : TDictIntType):TDictIntType;inline;
begin result := i*ccInitialSize+17;//random(i); end;
Delphi-Quellcode:
Ich erhalte auch so keine Fehlermeldung mit Freepascal 2.6.0 /Win7
program DictFind;
{$IFDEF FPC} {$MODE DELPHI} {$OPTIMIZATION ON} {$OPTIMIZATION REGVAR} {$OPTIMIZATION PEEPHOLE} {$OPTIMIZATION CSE} {$OPTIMIZATION ASMCSE} {$ELSE} {$APPTYPE CONSOLE} {$ENDIF} uses sysutils,csDictionary; const LAENGE = 25*1000*1000; RANDOMRANGE = 1000*100; // RANDOMRANGE = High(tDictIntType); type tArr64 = array of TDictIntType; var t1,t0,dt : TDateTime; Wert : TDictIntType; dummy : Pointer; i,j: integer; A64 : tarr64; TestHash : TIntegerDictionary; function myRandom(i : TDictIntType):TDictIntType;inline; begin result := i*ccInitialSize+17;//random(i); end; BEGIN randomize; setlength(A64 ,LAENGE); TestHash:= TIntegerDictionary.create; t0 := time; For i := low(A64) to High(A64) do Wert := myrandom(i);//random(RANDOMRANGE); t1 := time; dt := t1-t0; Write('Erzeugen von ',LAENGE,' Zufallszahlen [0..',Randomrange-1); writeln(FormatDateTime('] hh:nn:ss,zzz',dt)); t0 := time; j := low(A64); For i := low(A64) to High(A64) do begin Wert := myrandom(i);//myrandom(RANDOMRANGE); IF TestHash.Add(Wert,Pointer(j)) then begin A64[j] := Wert; inc(j); end; end; setlength(A64,j); t1 := time; Write('TotalCOunt :',TestHash.TotalCount:10); Write('Einfuegen von ',j,' verschiedenen Daten in '); writeln(FormatDateTime(' hh:nn:ss,zzz',t1-t0-dt)); For i := low(A64) to 10 do writeln(i:10,A64[i]:20,TestHash.find(A64[i],dummy):8,integer(dummy):10); writeln(j-1:10,A64[j-1]:20,TestHash.find(A64[j-1],dummy):8,integer(dummy):10); t0 := time; testHash.free; t1 := time; Write('Aufloesen der Hashmap in '); Writeln(FormatDateTime('hh:nn:ss,zzz',t1-t0)); setlength(A64,0); readln; END. Gruß Horst |
AW: Hashtable, wie benutzen?
Zitat:
Zitat:
Vermutlicher Grund: - der Zeiger "Result" ist defekt und zeigt sonstwohin - der Zeiger "Result" steht auf nil, was natürlich zum knallen führt Letzeres hätte man über die Fehlermeldung (die keiner kennt) leicht rausbekommen und mit dem Debugger gegenprüfen können. |
AW: Hashtable, wie benutzen?
Hallo,
hier die Funktion bei Zeile 535:
Delphi-Quellcode:
Der Wert NIL wird abgefangen.
Function TIntegerDictionary.FindHash(aKey : TDictIntType; Out h: Cardinal): Pointer;
Begin h := HashFromInt(aKey) Mod fHashMod; Result := fHashList[h]; While PIntHashEntry(Result) <> Nil Do With PIntHashEntry(Result)^ Do If heKey = aKey Then Exit Else Result := heNext; End; Was eventuell helfen könnte, ein paar unnötige Begin/end einzubauen, damit das with sich auch garantiert auf den else-Teil erstreckt, aber diese Zeiten sind doch wohl lange vorbei...
Delphi-Quellcode:
Man kann ja in der Zeile " If heKey = aKey Then" mit F9 einen Breakpoint setzen und dann mal laufen lassen.
Function TIntegerDictionary.FindHash(aKey : TDictIntType; Out h: Cardinal): Pointer;
Begin h := HashFromInt(aKey) Mod fHashMod; Result := fHashList[h]; While PIntHashEntry(Result) <> Nil Do Begin With PIntHashEntry(Result)^ Do Begin If heKey = aKey Then Exit Else Result := heNext; end; end; End; Gruß Horst |
AW: Hashtable, wie benutzen?
Zitat:
Zitat:
Zitat:
Du willst vermutlich darauf hinaus, das die Problembeschreibung etwas knapp ist. Da hast Du sicherlich Recht, aber im Kontext reicht es. Das Testprogramm wäre es noch wert, gepostet zu werden. Oder man verwendet mal FastMM mit Sentinel, um zu prüfen, ob Speicherbereiche überschrieben werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:27 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz