Zitat von
Medium:
Eine doppelt verkettete echte Liste macht hingegen genau keinen Unterschied dabei, ob ich nun hinten anfüge oder in der Mitte etwas zwischenhänge. Ohne jeweils passende Datenstrukturen nützt der ganze Vergleich leider nichts.
Verkettete Listen kann man nicht binär durchsuchen. Wir vergleichen Verfahren und die binäre Suche benötigt nun mal ein Array, scheidet also *aus*.
Zitat von
Medium:
Letztlich will ich hier ja garkeinen Flamewar zwischen binärer Suche und Hashmaps anzetteln,
Flamewares gibts bei mir nicht.
Zitat von
Medium:
sondern nur darauf hinweisen, dass Hashmaps nicht in jedem Fall das nun plus ultra sind.
Mir ist kein Fall bekannt. Wenn ich nur einige Tausend Werte habe und ich sofort eine sortierte Liste möchte, ist eine Array-Struktur mit BS natürlich praktischer. Schneller ist es in keinem mir bekannten Fall.
Zitat von
Medium:
Auch gibt es einen gewissen Overhead, dass in Kollisionsfällen doch wieder Listen zum Einsatz kommen, und damit in sehr degenerierten Fällen eine Hashmap wieder zu einer Liste machen.
Dieser Overhead führt zu einem Faktor von ca. 1.1 anstelle von 1.0.
Ich kann jedoch einen theoretische Worstcase konstruieren, wenn ich die Hash-Funktion der Hashmap kenne, und dafür sorge, das meine Schlüssel immer auf dem gleichen Bucket landen. Dieser Worstcase kommt aber in der Realität eigentlich nie vor.
Zitat von
Medium:
(Dabei ist dann die Länge des Hashes, also indirekt der Speicherbedarf wieder interessant.)
Der Hash wird nicht gespeichert, sondern dient zur Berechnung des Indexes in der Hashmap.
Zitat von
Medium:
Insbesondere die implizite Sortierung dürfte der binären Suche (bzw. ihren Verbesserungen, die du bislang nicht beachtet hast) einen großen Pluspunkt verschaffen, weil zumindest is sehr vielen Anwendungen mit derart vielen Daten letztlich eine Sortierung mindestens wünschenswert ist (um z.B. Daten in einer bestimmten Range auszugeben etc.).
Nein. Hinterher einmalig Sortieren ist immer schneller, als ständig die Ordnung der Liste zu gewährleisten.
Zitat von
Medium:
Die Wahl ist daher stark von der Beschaffenheit der Datenmenge, und dem Einsatzzweck abhängig.
Auch falsch. Es gibt nur einen sehr sehr seltenen Fall: Die Schlüssel mappen auf immer die gleichen Buckets. Bei Strings ist das sehr unwahrscheinlich (ELF-Hash), bei Zahlen als Schlüssel müssten diese bei meiner Implementierung immer ein Vielfaches der aktuell internen Länge der Hashmap (Primzahl) sein. Beides ist verdammt selten in freier Wildbahn anzutreffen
Zitat von
Medium:
Dass du das nicht-lineare Verhalten einfach ignorierst ist ungenügend, da die binäre Suche immer nichtlinear ist.
Meine Rechnung stimmt auch bei der Vereinfachung. Die korrekte Zahl liegt bei ca. 17 Mio. Die 19 Mio als Überschlag sind also innerhalb eines Fehlers von 10%. Nicht schlecht für eine grobe Schätzung.
Zitat von
Medium:
Ich weiss nicht, wie du zu einem anderen Schluss kommst hier. Bei 1 Mio vorhanderer Einträge, weisst du gesichert nach spätestens 20 Vergleichen, wo dein Wert steht, bzw. wo er eingefügt werden muss um die Sortierung beizubehalten.
Du meinst, über den WorstCase eine Entscheidung über die Güte eines Verfahrens fällen zu können. Ich nehme den Normalfall, denn das tritt in der Praxis nun mal auf. Ich schlage vor, Du verwendest einfach mal eine Hashmap. Du wirst sehen, um wie viel schneller deine Anwendungen werden. Wenn es Dir um den WC geht, dann verwende eine SkipList, die reorganisiert sich selbst.
Bei den von Dir erwähnten Verbesserungen hätte man weniger Vergleiche, aber *immer* mehr als bei einer Hashmap. Weiterhin kenne ich keine Implementierung, die eine der erwähnten Suchverfahren auf einer verketteten Liste anwenden kann, wir haben es hier also letztendlich mit Arrays zu tun, die dann nicht zu gebrauchen sind.
Natürlich sind deine Überlegungen bezüglich des WC richtig, aber wenn der WC in der Praxis nicht vorkommt, dann ist das irrelevant. Jede Hash-Funktion hat einen WC (zwei Strings mappen auf den selben Wert). Werden sie deshalb nicht eingesetzt? Jeder Quicksort auch. Trotzdem verwendet man ihn. Und eine Hashmap hat einen extrem lahmen Worst Case, trotzdem sind die Teile im Einsatz, wie eben ein Quicksort oder ein KMP-Search etc.
Meine Demo simuliert die vom Fragesteller thematisierte Problematik: Es werden Häufigkeiten gezählt. Da interessiert mich irgend ein Worst Case oder eine theoretische Berechnung nicht. Ich starte und schaue auf das Ergebnis.
In der ersten Version habe ich einfach aufsteigend die 'i mod X' gezählt, das führt bei der BS zum Worst Case und ist insofern unfair. Also habe ich eine neue Version eingestellt, die Zufallszahlen (jeweils mit gleichem Seed) zählt. Die Ergebnisse sind immer noch so, das man das BS letztendlich in die Tonne treten kann. Wenn Du natürlich eine deiner Suchverfahren mit einer verketteten Liste durchführen kannst, wäre das Ergebnis zwar immer noch langsamer als eine Hashmap, dafür hätten wir aber eine Struktur mit einem akzeptablen weil deterministischen Worst Case. Diese Implementierung würde ich dann als akzeptable Alternative zu Hashmaps, Skiplisten, DAWGs etc. ansehen.