![]() |
Zusätzliches WOrt in Hashtabelle einfügen?
Hallo,
in diesem Quelltext gibt es eine Hashtabelle mit den in Pascal reservierten Wörtern. Allerdings fehlt das Wort "ASM". An welcher Stelle muss ich das einfügen, damit der hier verwendete Algo das eigefügte Wort auch findet und ohne die bisherige Wortfolge für den verwendeten Algo unbrauchbar zu machen. Hier ist die Quelle:
Delphi-Quellcode:
Aus dem Quellcode werde ich da nicht schlau. Wo gibt es Literatur zu diesem Thema, aber bitte praxisnah.
unit Reserved {word or directive identificator };
{ Under GNU License } { JOAO PAULO SCHWARZ SCHULER } { http://www.schulers.com } { Turbo Pascal Source } { Free Pascal Source for DOS } { Free Pascal Source for Linux } { Delphi Source } interface Const HashingNumber = 23; MaxOnHashLine = 10; type STR20 = string[20]; Const RWords : array[0..HashingNumber-1,0..MaxOnHashLine-1] of str20 = ( {00} ('CONST','OR','TYPE','','','','','','',''), {01} ('SHL','FOR','DESTRUCTOR','INHERITED','PROPERTY','','','','',''), {02} ('TO','OBJECT','TRY','CDECL','','','','','',''), {03} ('VAR','ASSEMBLER','','','','','','','',''), {04} ('AND','FORWARD','THEN','IMPLEMENTATION','LIBRARY','RAISE','','','',''), {05} ('IF','UNTIL','PUBLISHED','STORED','','','','','',''), {06} ('SET','CLASS','INITIALIZATION','THREADVAR','','','','','',''), {07} ('LABEL','PROGRAM','SHR','FINALIZATION','NODEFAULT','','','','',''), {08} ('CASE','END','DISPID','INDEX','RESIDENT','','','','',''), {09} ('ABSOLUTE','WHILE','DO','AUTOMATED','','','','','',''), {10} ('RECORD','PACKED','INLINE','PUBLIC','PRIVATE','AS','FAR','OVERRIDE','',''), {11} ('OF','STRING','NOT','DEFAULT','DYNAMIC','MESSAGE','','','',''), {12} ('FILE','REPEAT','BEGIN','','','','','','',''), {13} ('IN','EXTERNAL','INTERFACE','EXPORTS','NAME','STDCALL','','','',''), {14} ('GOTO','PROCEDURE','','','','','','','',''), {15} ('DOWNTO','ARRAY','PROTECTED','','','','','','',''), {16} ('FUNCTION','','','','','','','','',''), {17} ('MOD','WITH','','','','','','','',''), {18} ('IS','NEAR','','','','','','','',''), {19} ('XOR','CONSTRUCTOR','','','','','','','',''), {20} ('DIV','NIL','EXCEPT','','','','','','',''), {21} ('ELSE','UNIT','USES','FINALLY','ABSTRACT','','','','',''), {22} ('EXPORT','PASCAL','VIRTUAL','','','','','','','')); function Key(S:string;Divisor:byte):word; {calculates de hashing code} { calcula chave de acesso } function GetHash(S:String):word; function IsReserved(S:string):boolean; { checks if S is a Reserved word or a directive} implementation function Key(S:string;Divisor:byte):word; { calcula chave de acesso } var I:integer; SOMA:longint; begin SOMA:=0; for I:=1 to length(S) do inc(SOMA,ord(S[I])); Key:=SOMA mod Divisor; end; function GetHash(S:String):word; begin GetHash:=Key(S,HashingNumber); end; function IsReserved(S:string):boolean; { checks if S is a Reserved word or a directive} var HN,L:word; C:word; Found:boolean; begin L:=Length(S); for C:=1 to L do S[C]:=UpCase(S[C]); HN:=GetHash(S); C:=0; Found:=false; while (C<MaxOnHashLine) and (RWORDS[HN,C]<>'') and not(Found) do begin Found:=Found or (S=RWORDS[HN,C]); inc(C); end; IsReserved:=Found; end; end. {of unit} Oder ist die Einfügestelle völlig egal. Key berechnet dann einen Hashwert, abhängig von der Einfügestelle und dem Wort. Allerdings kann ich mir nicht wirklich vostellen, das der Einfügeort echt egal ist. Eher glaube ich das die beherigen Pascal Wörter algo-bedingt an ebendiesen Stellen stehen müssen. Wer kann hier Licht ins Dunkel bringen? Ich möchte gerne das fehlende Wort 'ASM' ergänzen und wenn ich später noch andere fehlende Wörter finden sollte, diese auch ergänzen. Die Konstante RWords enthält die Hash-Tabelle. . |
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Den Index der Zeile, in der ein
Delphi-Quellcode:
stehen muss, gibt
Wort
Delphi-Quellcode:
an.
GetHash(Wort)
Delphi-Quellcode:
ergibt 18. Also muss
GetHash('ASM')
Delphi-Quellcode:
in die Zeile
'ASM'
Delphi-Quellcode:
eingefügt werden, und zwar so, dass das erste
{18}
Delphi-Quellcode:
ersetzt wird:
''
Delphi-Quellcode:
{18} ('IS','NEAR','ASM','','','','','','',''),
|
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Danke wie verrückt. So füge ich also ein neues Wort ein, indem ich den Hash Wert mit GetHash() ermittle und dann einen Index (hier 18) in die Tabelle erhalte. Dann füge ich das neue Wort da ein, wo das erste '' ist. Verstanden. Von da ais sind es nicht allzu viele Wörter in der Tabellenzeile, dürfte also dann schnell gefunden sein.
|
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Wahrscheinlich wäre eine lineare Suche bei der geringen Anzahl an Schlüsseln nicht langsamer als diese Hashtabelle.
Ausserdem wird enthält das Array RWords jede Menge Luft (23*10*(20+1) = 4830 Bytes); die lineare Suche bräuchte nicht mal ein Viertel davon. |
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Zitat:
|
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Zitat:
Ich hab's mal ausprobiert: Fast dreimal so schnell, wie die Lösung mit Hashtable. |
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Ich denke es hängt auch davon ab, ob die Menge an Schlüsseln sich nie verändert oder ob zur Laufzeit Schlüssel hinzugefügt oder entfernt werden sollen.
a.) feste Menge an Schlüsseln -> binäre Suche, Interpolationssuche oder quadratische Binärsuche liefert das beste Ergebnis b.) zur Laufzeit wird eine begrenzte Menge an Schlüsseln hinzugefügt -> Hashverfahren können genützt werden Bei zu hohem Füllungsgrad der Hashtabelle wird die Suche aber langsam. c.) zur Laufzeit dürfen auch Schlüssel gelöscht werden -> Hashverfahren versagen, weil das Löschen von Schlüsseln nicht erlaubt ist |
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Zitat:
Hashtabellen (nicht gerade diese) sind in Puncto Performance bei großen Datenmengen nicht zu schlagen. Die Performance für das Einfügen, Suchen und Löschen ist stehts O(1), sofern eine dynamische Variante genutzt wird. Nur bei kleinen Datenmengen macht sich der overhead der Hashfunktion bemerkbar, hier sind vor allem einfache Verfahren im Vorteil. Bei einem Scanner/Lexer/Tokenizer würde ich auf jeden Fall eine Hashmap nehmen, wobei ich nicht nur die Wörter speichern würde, sondern gleich auch noch die Kategorie, also 'reserved word','Zahl','Symbol','Identifier' etc. Der ist zwar anfangs langsamer, aber da ich den beim Scanner befülle, sollte ich unterm Strich besser fahren. Ich habe es nun einmal verglichen und bei mir ist diese angeblich so blöde Variante die Schnellste. Verglichen habe ich das Suchen in: Dieser Implementierung, einer Dictionary, einer sortierte Stringlist und einem unsortieres Array. Die Idee bei diesem hier gezeigten Verfahren ist es ja, die Wortliste durch eine Unterteilungsfunktion in kleinere Listen zu zerteilen: Wenn man als Funktion einfach das erste Zeichen nimmt (und die Liste umsortiert), wird die Geschichte um 35% schneller. Und wenn man den ShortString gegen einen normalen String tauscht, wird das 4x so schnell. |
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Zitat:
|
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Hi
Mit Const und AnsiString und UpperCase statt der Schleife ist es nicht mehr 4x so schnell, sondern nur noch 2,5x so schnell |
AW: Zusätzliches WOrt in Hashtabelle einfügen?
Zitat:
Die Hashfunktion bildet den Schlüssel auf den Index im Array ab. Sollte ein Bucket aber schon belegt sein, dann nimmt man den nächsten freien Eintrag. ("Linear Probing") Bei zu hohem Füllungsgrad; also das Array ist schon zu 80% voll; wird immer seltener ein freies Bucket gefunden. Es bilden sich ganze Ketten von belegten Buckets, die das Suchen und Eintragen von Schlüsseln verlangsamen. Bei 100% Belegung müssen für die Suche nach einem nichtvorhandenen Schlüssel ALLE Buckets durchsucht werden. Natürlich kann man Hashtabellen auch anderst strukturieren, z.B. als Array of TList und damit einige dieser Nachteile vermeiden. Ansonsten ist nach meinen Messung die lineare Suche bei diesem Beispiel schneller!
Delphi-Quellcode:
Die Hashtabelle aus Beitrag #1 benötigt ~ 1,32 Sekunden,
for i := 1 to 1000000 do
begin IsReserved('test'); // Miss IsReserved('string'); // Hit end; die lineare Suche braucht ~ 1,02 Sekunden. Wer selbst messen möchte:
Delphi-Quellcode:
function IsReservedLinSearch(S:string):Boolean;
const list : array[0..87] of string = ( 'CONST','OR','TYPE', 'SHL','FOR','DESTRUCTOR','INHERITED','PROPERTY', 'TO','OBJECT','TRY','CDECL', 'VAR','ASSEMBLER', 'AND','FORWARD','THEN','IMPLEMENTATION','LIBRARY','RAISE', 'IF','UNTIL','PUBLISHED','STORED', 'SET','CLASS','INITIALIZATION','THREADVAR', 'LABEL','PROGRAM','SHR','FINALIZATION','NODEFAULT', 'CASE','END','DISPID','INDEX','RESIDENT', 'ABSOLUTE','WHILE','DO','AUTOMATED', 'RECORD','PACKED','INLINE','PUBLIC','PRIVATE','AS','FAR','OVERRIDE', //50 'OF','STRING','NOT','DEFAULT','DYNAMIC','MESSAGE', 'FILE','REPEAT','BEGIN', 'IN','EXTERNAL','INTERFACE','EXPORTS','NAME','STDCALL', 'GOTO','PROCEDURE', 'DOWNTO','ARRAY','PROTECTED', 'FUNCTION', 'MOD','WITH', 'IS','NEAR', 'XOR','CONSTRUCTOR', 'DIV','NIL','EXCEPT', 'ELSE','UNIT','USES','FINALLY','ABSTRACT', 'EXPORT','PASCAL','VIRTUAL' ); var i : Integer; begin S := Uppercase(S); for i := low(List) to High(List) do begin if S = list[i] then begin Result := True; Exit; end; end; Result := False; end; |
AW: Zusätzliches WOrt in Hashtabelle einfügen?
[QUOTE=shmia;1167302]
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Er sucht nach allen reservierten Wörtern. Wir können noch ein paar Wörter hinzupacken, die nicht gefunden werden sollen, wenn Du magst. Oder Du schlägst einen anderen Test vor.
for i := 1 to 1000000 do
for j := 0 to allReservedWordsCount-1 do IsReserved(reservedWords[j]); Dein Test zeigt aber sehr deutlich, das lineare Suche bei kleinen Listen nicht zu topppen ist. Eine Liste mit 88 Elemente ist hier aber nicht mehr "klein". Der Test mit folgender Klasse führt bei mir zu erheblichen Geschwindigkeitszuwächsen und hält sich bezüglich Speicherauslastung in Grenzen:
Delphi-Quellcode:
Unit pascalKeywordList;
Interface Type TKeywordBucket = Record data: Array[0..10] Of String; dataCount: Integer; End; // A generic chaining hash map using the first character as hash function. TKeywordListHash = Array[Char] Of TKeywordBucket; TPascalKeywordList = Class private keywords: TKeywordListHash; Procedure FillList; public Constructor Create; Function IsReserved(Const aWord: String): Boolean; End; Implementation Const keywordCount = 88; keywordList: Array[0..keyWordCount - 1] Of String = ( 'CONST', 'OR', 'TYPE', 'SHL', 'FOR', 'DESTRUCTOR', 'INHERITED', 'PROPERTY', 'TO', 'OBJECT', 'TRY', 'CDECL', 'VAR', 'ASSEMBLER', 'AND', 'FORWARD', 'THEN', 'IMPLEMENTATION', 'LIBRARY', 'RAISE', 'IF', 'UNTIL', 'PUBLISHED', 'STORED', 'SET', 'CLASS', 'INITIALIZATION', 'THREADVAR', 'LABEL', 'PROGRAM', 'SHR', 'FINALIZATION', 'NODEFAULT', 'CASE', 'END', 'DISPID', 'INDEX', 'RESIDENT', 'ABSOLUTE', 'WHILE', 'DO', 'AUTOMATED', 'RECORD', 'PACKED', 'INLINE', 'PUBLIC', 'PRIVATE', 'AS', 'FAR', 'OVERRIDE', 'OF', 'STRING', 'NOT', 'DEFAULT', 'DYNAMIC', 'MESSAGE', 'FILE', 'REPEAT', 'BEGIN', 'IN', 'EXTERNAL', 'INTERFACE', 'EXPORTS', 'NAME', 'STDCALL', 'GOTO', 'PROCEDURE', 'DOWNTO', 'ARRAY', 'PROTECTED', 'FUNCTION', 'MOD', 'WITH', 'IS', 'NEAR', 'XOR', 'CONSTRUCTOR', 'DIV', 'NIL', 'EXCEPT', 'ELSE', 'UNIT', 'USES', 'FINALLY', 'ABSTRACT', 'EXPORT', 'PASCAL', 'VIRTUAL'); { TPascalKeywordList } Constructor TPascalKeywordList.Create; Begin FillList; End; Procedure TPascalKeywordList.FillList; Var i: Integer; Procedure _FillIntoList(Const keyWord: String); Begin Assert(Length(keyWord) > 1, 'the keyword to be filled in may not be empty'); With keywords[keyword[1]] Do Begin data[dataCount] := keyWord; inc(dataCount); End End; Begin For I := 0 To keywordCount - 1 Do _FillIntoList(keyWordList[i]); End; Function TPascalKeywordList.IsReserved(Const aWord: String): Boolean; Var i: Integer; Begin Assert(Length(aWord) > 1, 'the word to be searched may not be empty'); With keywords[aWord[1]] Do For I := 0 To dataCount - 1 Do If data[i] = aWord Then Begin result := true; exit; End; result := false; End; End. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:13 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-2025 by Thomas Breitkreuz