C # Binary Trees und Wörterbücher

stimmen
15

Ich kämpfe mit dem Begriff der, wenn binäre Suchbäume zu verwenden und wenn Wörterbücher zu verwenden.

In meiner Anwendung habe ich ein kleines Experiment, das die C5 - Bibliothek verwendet TreeDictionary(die ich ist ein rot-schwarz binären Suchbaum glaube) und den C # Wörterbuch. Das Wörterbuch war immer schneller auf Add / Operationen finden und auch immer weniger Speicherplatz verwendet. Zum Beispiel bei 16.809 <int, float>Einträgen, verwendete das Wörterbuch 342 KiB , während des Baumes verwendet 723 KiB.

Ich dachte, dass BST sollte mehr Speicher effizient sein, aber es scheint, dass ein Knoten des Baumes mehr Bytes als ein Eintrag in einem Wörterbuch erfordert. Was gibt? Gibt es einen Punkt, an dem BST sind besser als Wörterbücher?

Auch als Neben Frage, weiß jemand , ob es eine schnellere + mehr Speicher effiziente Datenstruktur zum Speichern von <int, float>Paaren für Wörterbuchtyp Zugriff als eine der beiden genannten Strukturen?

Veröffentlicht am 28/01/2010 um 02:46
quelle vom benutzer
In anderen Sprachen...                            


6 antworten

stimmen
1

Es scheint mir, Ihnen eine vorzeitige Optimierung tun.

Was würde ich Ihnen vorschlagen, ist eine Schnittstelle zu erstellen, zu isolieren, welche Struktur Sie tatsächlich verwenden und dann die Schnittstelle implementieren, um die Dictionary (die am besten zu funktionieren scheint).

Wenn der Speicher / Leistung wird ein Problem (was wahrscheinlich nicht für 20k- Zahlen), dann können Sie andere Schnittstellenimplementierungen erstellen und prüfen, welche Bestleistungen funktioniert. Sie werden nicht fast alles, was in dem Rest des Codes ändern müssen (außer dem mit der Umsetzung Sie verwenden).

Beantwortet am 28/01/2010 um 03:26
quelle vom benutzer

stimmen
1

Es macht Sinn , dass ein Baumknoten mehr Speicherplatz als ein Wörterbucheintrag erfordern würde. Ein Binärbaum Knoten muss den Wert speichern und sowohl die linken und rechten Teilbäume. Die generische Dictionary<TKey, TValue>wird als Hash - Tabelle implementiert , die - Ich gehe davon aus - entweder verwendet eine verknüpfte Liste für jede Schaufel (Wert plus einen Zeiger / Referenz) oder irgendeine Art von Remapping (nur der Wert). Ich würde einen Blick in Reflector müssen sicher sein, aber für die Zwecke dieser Frage , die ich glaube nicht , es ist so wichtig.

Die spärliche die Hash-Tabelle, die weniger effizient im Hinblick auf dem Lager- / Speicher. Wenn Sie eine Hash-Tabelle (Wörterbuch) erstellen und initialisieren seine Kapazität auf 1 Million, und es nur mit 10.000 Elementen füllen, dann bin ich ziemlich sicher, es wäre viel mehr Speicher als ein BST mit 10.000 Knoten auffressen.

Dennoch würde ich nichts davon befürchten, wenn die Menge von Knoten / Schlüssel nur in den Tausenden ist. Das wird in dem Kilobyte gemessen werden, im Vergleich zu Gigabyte physischem RAM.


Wenn die Frage lautet: „Warum würden Sie wollen, statt einer Hash-Tabelle einen binären Baum benutzen?“ Dann IMO die beste Antwort ist, dass binäre Bäume bestellt werden, während Hash-Tabellen nicht. Sie können nur eine Hash-Tabelle für Schlüssel suchen, die genau gleich etwas sind; mit einem Baum, können Sie sich für einen Wertebereich, nächsten Wert suchen, usw. Dies ist eine ziemlich wichtige Unterscheidung, wenn Sie einen Index oder etwas ähnliches sind zu schaffen.

Beantwortet am 28/01/2010 um 03:39
quelle vom benutzer

stimmen
0

Die Schnittstelle für einen Baum und eine Hash-Tabelle (was ich vermute, ich ist, was Ihr Wörterbuch one basiert) sollte sehr ähnlich sein. Immer rund um verkeilt Lookups.

Ich hatte immer gedacht, ein Wörterbuch besser war, die Dinge einmal für das Erstellen und dann dann viele Lookups auf es zu tun. Während ein Baum besser war, wenn man es deutlich wurde modifiziert. Allerdings weiß ich nicht, wo ich diese Idee abgeholt.

(Funktionale Sprachen verwenden oft Bäume als Grundlage für sie Sammlungen wie Sie die meisten der Baum wieder verwenden können, wenn Sie kleine Änderungen zu machen).

Beantwortet am 28/01/2010 um 03:40
quelle vom benutzer

stimmen
0

Sie vergleichen nicht „Äpfel mit Äpfeln“, ein BST werden Ihnen eine geordnete Darstellung , während ein Wörterbuch ermöglicht es Ihnen , einen Lookup auf einem Schlüsselwertpaar zu tun (in diesem Fall).

Ich würde nicht viel Größe in der Speicherbedarf erwarten zwischen 2, aber das Wörterbuch gibt Ihnen eine viel schnellere Lookup. Um ein Element in einem BST finden Sie (möglicherweise) müssen den gesamten Baum zu durchqueren. Aber eine dictnary Lookup zu tun Lookup Sie einfach basierend auf dem Schlüssel.

Beantwortet am 28/01/2010 um 04:05
quelle vom benutzer

stimmen
8

Ich dachte, dass BST sollte mehr Speicher effizient sein, aber es scheint, dass ein Knoten des Baumes mehr Bytes als ein Eintrag in einem Wörterbuch erfordert. Was gibt? Gibt es einen Punkt, an dem BST sind besser als Wörterbücher?

Ich habe persönlich nie von einem solchen Prinzip gehört. Sogar noch, es ist nur ein allgemeiner Grundsatz, keine kategorische Tatsache in dem Gewebe des Universums geätzt.

Im Allgemeinen Wörterbücher ist wirklich nur ein schicker Wrapper um eine Reihe von verknüpften Listen. Sie fügen in das Wörterbuch so etwas wie:

LinkedList<Tuple<TKey, TValue>> list =
    internalArray[internalArray % key.GetHashCode()];
if (list.Exists(x => x.Key == key))
    throw new Exception("Key already exists");
list.AddLast(Tuple.Create(key, value));

So ist es fast O (1) -Operation. Das Wörterbuch verwendet , O (internalArray.Length + n) Speicher, wobei n die Anzahl der Elemente in der Sammlung ist.

Im Allgemeinen BSTs kann realisiert werden:

  • verketteten Listen, der O (n) Raum zu verwenden, wobei n die Anzahl Elemente in der Sammlung ist.
  • Arrays , die verwendet wird O (2 h - n) Raum , wo h die Höhe des Baumes ist und n die Anzahl der Elemente in der Sammlung ist.
    • Da Rot-Schwarz - Bäume eine beschränkte Höhe von O (1,44 * n) haben, sollte ein Array Implementierung eine beschränkte Speichernutzung von etwa O hat (2 1.44n - n)

Quoten sind, wird die C5 TreeDictionary mit Arrays implementiert, die wahrscheinlich verantwortlich für den verschwendeten Speicherplatz ist.

Was gibt? Gibt es einen Punkt, an dem BST sind besser als Wörterbücher?

Wörterbücher haben einige unerwünschte Eigenschaften:

  • Es kann nicht genug continugous Speicherblocks sein Ihr Wörterbuch zu halten, auch wenn seine Speicheranforderungen sind viel weniger als als die gesamte verfügbare RAM.

  • Auswerten der Hash - Funktion kann eine beliebig lange Zeitspanne dauern. Streicher, zum Beispiel verwenden Reflector die untersuchen System.String.GetHashCodeMethode - Sie werden bemerken , eine Zeichenfolge immer nimmt O (n) Zeit Hashing, was bedeutet es viel Zeit für sehr lange Strings nehmen. Auf der einen Seite, Strings für Ungleichheit Vergleich fast immer schneller als Hashing, da es bei nur die ersten paar Zeichen suchen erfordern. Sein ganz möglich Baum Einsätze als Wörterbuch Einsätze schneller sein , wenn Hash - Code - Auswertung zu lange dauert.

    • Int32 Die GetHashCodeMethode ist buchstäblich nur return this, so würden Sie hardpressed werden , um einen Fall zu finden , wo eine Hash - Tabelle mit int Schlüssel ist langsamer als ein Baum Wörterbuch.

RB Bäume haben einige wünschenswerte Eigenschaften:

  • Sie können die Min- und Max-Elemente in O (log n) Zeit, im Vergleich zu O (n) Zeit mit einem Wörterbuch finden / entfernen.

  • Wenn ein Baum als verkettete Liste implementiert ist eher als ein Array, ist der Baum in der Regel mehr Platz effizienter als ein Wörterbuch.

  • Ebenso seine lächerlich einfach unveränderliche Versionen von Bäumen zu schreiben , die insert / Lookup unterstützen / Löschen in O (log n) Zeit. Wörterbücher passen sich nicht gut an Unveränderlichkeit, da Sie die gesamte interne Array für jeden Betrieb kopieren müssen (eigentlich ich habe einige Array-basierte gesehen Implementierungen von unveränderlichen Finger Bäume, eine Art Allzweck - Wörterbuch - Datenstruktur, aber die Umsetzung ist sehr Komplex).

  • Sie können alle Elemente in einem Baum in sortierter Reihenfolge in konstantem Raum und O (n) Zeit durchqueren, während Sie eine Hash-Tabelle in eine Array-Dump bräuchten und sortiert sie die gleiche Wirkung zu erzielen.

So hängt die Wahl der Datenstruktur wirklich auf welche Eigenschaften Sie benötigen. Wenn Sie nur eine ungeordnete Tasche wollen und können garantieren, dass Ihre Hash-Funktion schnell bewerten, geht mit einem .Net Wörterbuch. Wenn Sie eine geordnete Tasche benötigen oder eine langsam laufende Hash-Funktion, geht mit TreeDictionary.

Beantwortet am 28/01/2010 um 04:16
quelle vom benutzer

stimmen
0

Eine ausgewogene BST ist vorzuziehen, wenn Sie Ihre Datenstruktur aus der Latenz Spikes und Hash-Kollisionen Angriffen schützen müssen.

Das erstere geschieht, wenn ein Array-backed-Struktur wächst eine Größe verändert wird, wobei die letztere ist eine unvermeidliche Eigenschaft des Algorithmus als Projektion von unendlichen Raum bis zu einem begrenzten ganzzahligen Bereich Hashing.

Ein weiteres Problem in .NET ist, dass es LOH, und mit einem ausreichend großen Wörterbuch, das Sie laufen in eine LOH Fragmentierung. In diesem Fall können Sie einen BST verwenden, einen Preis von größerer algorithmischer Komplexität der Klasse.

Kurz gesagt, mit einem BST durch die Zuteilung Haufen gesichert Sie worst case O (log (N)) Zeit mit hashtable Sie O (N) worst case Zeit.

BST kommt zu einem Preis von O (log (N)) durchschnittliche Zeit, schlechter Cache-Lokalität und mehr Heapzuweisungen, aber es Latenz garantiert hat und von Wörterbuch-Attacken und Speicherfragmentierung geschützt.

Bemerkenswert, dass BST ist auch ein Thema auf anderen Plattformen zu Speicherfragmentierung, einen Verdichtungs Garbage Collector nicht verwenden.

Wie für die Speichergröße ist die .NET Dictionary`2 Klasse mehr Speicher effizient, weil es Daten als Off-Heap verknüpften Liste gespeichert, die nur Wert speichert und Informationen gegenüber. BST hat Objekt-Header zu speichern (wie jeder Knoten eine Klasseninstanz auf dem Heap ist), zwei Zeiger, und einige Augmented Baumdaten für ausgeglichene Bäume. Zum Beispiel müßte ein rot-schwarz-Baum einen boolean interpretiert als Farbe (rot oder schwarz). Dies ist zumindest 6 Maschine Worten, wenn ich mich nicht irre. So kann jeder Knoten in einem Rot-Schwarz-Baum auf 64-Bit-System ist ein Minimum von:

3 Worte für die header = 24 Byte 2 Worte für die untergeordneten Zeiger = 16 Bytes 1 Wort für die Farbe = 8 Bytes mindestens 1 Wort für den Wert 8+ Bytes = 16 + 24 + 8 + 8 = 56 Bytes (8 Bytes wenn der Baum verwendet einen übergeordneten Knoten pointer).

Zugleich würde die minimale Größe des Wörterbucheintrag nur 16 Byte sein.

Beantwortet am 10/12/2018 um 13:18
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more