it-swarm.com.de

Was sind die weniger bekannten, aber nützlichen Datenstrukturen?

Es gibt einige Datenstrukturen, die wirklich nützlich sind, aber den meisten Programmierern unbekannt sind. Welche sind das?

Jeder kennt sich mit verknüpften Listen, Binärbäumen und Hashes aus, aber was ist zum Beispiel mit Listen überspringen und Bloom-Filter . Ich würde gerne mehr Datenstrukturen kennen lernen, die nicht so verbreitet sind, aber es lohnt sich zu wissen, weil sie auf großartigen Ideen beruhen und den Werkzeugkasten eines Programmierers bereichern.

PS: Ich interessiere mich auch für Techniken wie Dancing Links , die Eigenschaften einer gemeinsamen Datenstruktur geschickt nutzen.

EDIT: Bitte versuchen Sie, Links zu Seiten aufzunehmen, die die Datenstrukturen detaillierter beschreiben. Versuchen Sie auch, ein paar Wörter zu hinzuzufügen, warum eine Datenstruktur cool ist (wie Jonas Kölker bereits erwähnt). Versuchen Sie auch, eine Datenstruktur pro Antwort bereitzustellen. Auf diese Weise können die besseren Datenstrukturen allein aufgrund ihrer Stimmen an die Spitze gelangen.

796
f3lix

Tries , auch Präfix-Bäume oder Crit-Bit-Bäume genannt, gibt es seit über 40 Jahren, sind aber noch relativ unbekannt. Eine sehr coole Verwendung von Versuchen wird in " TRASH - Eine dynamische LC-Trie- und Hash-Datenstruktur " beschrieben, bei der ein Versuch mit einer Hash-Funktion kombiniert wird.

271
David Phillips

Bloom-Filter : Bit-Array von m Bits, anfangs alle auf 0 gesetzt.

Um ein Element hinzuzufügen, führen Sie es durch k Hash-Funktionen, die Ihnen k Indizes in dem Array geben, das Sie dann auf 1 setzen.

Um zu überprüfen, ob sich ein Element in der Menge befindet, berechnen Sie die Indizes k und überprüfen Sie, ob sie alle auf 1 gesetzt sind.

Dies gibt natürlich eine gewisse Wahrscheinlichkeit von Fehlalarmen (laut Wikipedia sind es ungefähr 0,61 ^ (m/n), wobei n die Anzahl der eingefügten Elemente ist). Falsch-Negative sind nicht möglich.

Das Entfernen eines Elements ist nicht möglich, aber Sie können counting bloom filter implementieren, dargestellt durch ein Array von Ints und Inkrementieren/Dekrementieren.

231
lacop

Rope : Dies ist eine Zeichenfolge, die billige Präfixe, Teilzeichenfolgen, mittlere Einfügungen und Anhänge ermöglicht. Ich habe es wirklich nur einmal benutzt, aber keine andere Struktur hätte ausgereicht. Regelmäßige Zeichenfolgen und Arrays im Voraus waren einfach viel zu teuer für das, was wir tun mussten, und es kam nicht in Frage, alles umzukehren.

140
Patrick

Listen überspringen sind ziemlich ordentlich.

Wikipedia
Eine Sprungliste ist eine probabilistische Datenstruktur, die auf mehreren parallelen, sortierten verknüpften Listen basiert und eine Effizienz aufweist, die mit einem binären Suchbaum vergleichbar ist (Auftragsprotokoll n durchschnittliche Zeit für die meisten Vorgänge).

Sie können als Alternative zu ausgeglichenen Bäumen verwendet werden (indem ein globaler Ausgleich anstelle einer strikten Durchsetzung des Ausgleichs verwendet wird). Sie sind einfach zu implementieren und schneller als ein rot-schwarzer Baum. Ich denke, sie sollten in jedem guten Programmierer-Toolchest enthalten sein.

Wenn Sie eine ausführliche Einführung in die Skip-Listen erhalten möchten, finden Sie hier einen Link zu einem Video Vortrag über die Einführung in Algorithmen des MIT.

Außerdem ist hier ein Java Applet, das Überspringen von Listen visuell demonstriert.

128
mmcdole

Spatial Indices , insbesondere R-trees und KD-trees , speichern räumliche Daten effizient. Sie eignen sich für geografische Kartenkoordinatendaten und VLSI-Orts- und Routenalgorithmen sowie manchmal für die Suche nach nächsten Nachbarn.

Bit Arrays Speichern Sie einzelne Bits kompakt und ermöglichen Sie schnelle Bitoperationen.

92
Yuval F

Reißverschlüsse - Ableitungen von Datenstrukturen, die die Struktur so modifizieren, dass sie den natürlichen Begriff "Cursor" haben - aktuelle Position. Diese sind wirklich nützlich, da sie garantieren, dass Hinweise nicht außerhalb der Grenzen liegen - verwendet werden, z. im xmonad window manager nachverfolgen, welches fenster fokussiert hat.

Erstaunlicherweise können Sie sie ableiten, indem Sie Techniken aus der Analysis anwenden auf den Typ der ursprünglichen Datenstruktur anwenden!

87
Don Stewart

Hier sind ein paar:

  • Suffix versucht. Nützlich für fast alle Arten der Zeichenfolgensuche ( http://en.wikipedia.org/wiki/Suffix_trie#Functionality ). Siehe auch Suffix-Arrays. Sie sind nicht ganz so schnell wie Suffix-Bäume, aber viel kleiner.

  • Spreizbäume (wie oben erwähnt). Der Grund, warum sie cool sind, ist dreifach:

    • Sie sind klein: Sie benötigen nur den linken und den rechten Zeiger, wie Sie es in einem Binärbaum tun (es müssen keine Knotenfarben- oder Größeninformationen gespeichert werden).
    • Sie sind (vergleichsweise) sehr einfach zu implementieren
    • Sie bieten eine optimale Komplexität für eine ganze Reihe von "Messkriterien" (Protokoll und Nachschlagezeit sind die, die jeder kennt). Siehe http://en.wikipedia.org/wiki/Splay_tree#Performance_theorems
  • Haufenweise sortierte Suchbäume: Sie speichern eine Reihe von (Schlüssel-, Prio-) Paaren in einem Baum, so dass es sich um einen Suchbaum in Bezug auf die Schlüssel und in Bezug auf die Prioritäten um einen Haufen handelt. Man kann zeigen, dass ein solcher Baum eine einzigartige Form hat (und nicht immer vollständig linksbündig gepackt ist). Mit zufälligen Prioritäten erhalten Sie die erwartete O (log n) Suchzeit (IIRC).

  • Eine Nische sind Adjazenzlisten für ungerichtete planare Graphen mit O(1) Nachbarabfragen. Dies ist weniger eine Datenstruktur als vielmehr eine bestimmte Art, eine vorhandene Datenstruktur zu organisieren. So geht's: Jedes ebene Diagramm hat einen Knoten mit höchstens Grad 6. Wählen Sie einen solchen Knoten aus, fügen Sie seine Nachbarn in die Nachbarliste ein, entfernen Sie ihn aus dem Diagramm und wiederholen Sie den Vorgang, bis das Diagramm leer ist. Wenn Sie ein Paar (u, v) haben, suchen Sie in der Nachbarliste von v nach u und in der Nachbarliste von u nach v. Beide haben eine Größe von höchstens 6, das ist also O (1).

Nach dem obigen Algorithmus haben Sie, wenn u und v Nachbarn sind, nicht sowohl u in der Liste von v als auch v in der Liste von u. Wenn Sie dies benötigen, fügen Sie einfach die fehlenden Nachbarn jedes Knotens zur Nachbarliste dieses Knotens hinzu, speichern Sie jedoch, wie viel der Nachbarliste Sie für eine schnelle Suche durchsuchen müssen.

69
Jonas Kölker

Ich denke, dass sperrenfreie Alternativen zu Standarddatenstrukturen, wie z. B. sperrenfreie Warteschlangen, Stapel und Listen, häufig übersehen werden.
Sie werden immer relevanter, da Parallelität eine höhere Priorität erhält und ein viel bewundernswerteres Ziel ist als die Verwendung von Mutexen oder Sperren für die gleichzeitige Verarbeitung von Lese-/Schreibvorgängen.

Hier sind einige Links
http://www.cl.cam.ac.uk/research/srg/netos/lock-free/
http://www.research.ibm.com/people/m/michael/podc-1996.pdf [Links zu PDF]
http://www.boyet.com/Articles/LockfreeStack.html

Mike Actons (oft provokanter) Blog enthält einige exzellente Artikel über schlossfreies Design und Vorgehensweisen

65
zebrabox

Ich denke Disjoint Set ist ziemlich geschickt für Fälle, in denen Sie eine Reihe von Elementen in verschiedene Mengen aufteilen und die Mitgliedschaft abfragen müssen. Eine gute Implementierung der Operationen Union und Find führt zu amortisierten Kosten, die praktisch konstant sind (umgekehrt zu Ackermnans Funktion, wenn ich mich richtig an meine Datenstrukturklasse erinnere).

55
Dana

Fibonacci-Haufen

Sie werden in einigen der schnellsten bekannten Algorithmen (asymptotisch) für viele grafische Probleme verwendet, z. B. für das Problem des kürzesten Pfads. Der Dijkstra-Algorithmus läuft in O (E log V) -Zeit mit Standard-Binärheaps. Die Verwendung von Fibonacci-Heaps verbessert dies auf O (E + V log V), was eine enorme Beschleunigung für dichte Graphen darstellt. Leider haben sie einen hohen konstanten Faktor, was sie in der Praxis oft unpraktisch macht.

52
Adam Rosenfield

Jeder, der Erfahrung mit 3D-Rendering hat, sollte mit BSP-Bäumen vertraut sein. Im Allgemeinen ist dies die Methode, bei der eine 3D-Szene so strukturiert wird, dass sie mit Kenntnis der Kamerakoordinaten und der Peilung verwaltet werden kann.

Binary Space Partitioning (BSP) ist eine Methode zur rekursiven Unterteilung eines Raums in konvexe Mengen durch Hyperebenen. Diese Unterteilung führt zu einer Darstellung der Szene mittels einer Baumdatenstruktur, die als BSP-Baum bekannt ist.

Mit anderen Worten, es ist eine Methode, um kompliziert geformte Polygone in konvexe Mengen oder kleinere Polygone aufzuteilen, die vollständig aus nicht reflektierenden Winkeln bestehen (Winkel kleiner als 180 °). Eine allgemeinere Beschreibung der Raumpartitionierung finden Sie unter Raumpartitionierung.

Ursprünglich wurde dieser Ansatz in der 3D-Computergrafik vorgeschlagen, um die Rendereffizienz zu erhöhen. Einige andere Anwendungen umfassen die Durchführung geometrischer Operationen mit Formen (konstruktive Volumengeometrie) im CAD, die Kollisionserkennung in Robotik- und 3D-Computerspielen sowie andere Computeranwendungen, die die Handhabung komplexer räumlicher Szenen beinhalten.

44
spoulson

Huffman-Bäume - wird zur Komprimierung verwendet.

43
Lurker Indeed

Schauen Sie sich Finger Trees an, besonders wenn Sie ein Fan der zuvor erwähnten rein funktionalen Datenstrukturen sind. Sie sind eine funktionale Darstellung persistenter Sequenzen, die den Zugriff auf die Enden in amortisierter konstanter Zeit und die Verkettung und zeitliche Aufteilung logarithmisch in der Größe des kleineren Teils unterstützen.

Wie pro der ursprüngliche Artikel :

Unsere funktionalen 2-3-Finger-Bäume sind ein Beispiel für eine von Okasaki (1998) eingeführte allgemeine Entwurfstechnik, die als implizite rekursive Verlangsamung bezeichnet wird. Wir haben bereits festgestellt, dass diese Bäume eine Erweiterung seiner impliziten Deque-Struktur darstellen und Paare durch 2-3 Knoten ersetzen, um die für eine effiziente Verkettung und Aufteilung erforderliche Flexibilität bereitzustellen.

Ein Fingerbaum kann mit einem Monoid parametrisiert werden, und die Verwendung verschiedener Monoide führt zu unterschiedlichen Verhaltensweisen für den Baum. Auf diese Weise können Finger Trees andere Datenstrukturen simulieren.

38
huitseeker

Circular oder Ring Buffer - wird unter anderem für das Streaming verwendet.

34
cdonner

Ich bin überrascht, dass niemand Merkle-Bäume erwähnt hat (dh Hash-Bäume ).

Wird in vielen Fällen verwendet (P2P-Programme, digitale Signaturen), in denen Sie den Hash einer gesamten Datei überprüfen möchten, wenn Ihnen nur ein Teil der Datei zur Verfügung steht.

<zvrba> Van Emde-Boas-Bäume

Ich denke, es wäre nützlich zu wissen, warum sie sind cool. Im Allgemeinen ist die Frage "warum" am wichtigsten;)

Meine Antwort lautet, dass Sie O (log log n) Wörterbücher mit {1..n} Schlüsseln erhalten, unabhängig davon, wie viele der Schlüssel verwendet werden. Genau wie die wiederholte Halbierung O (log n) ergibt, ergibt die wiederholte Quadrierung O (log log n), was im vEB-Baum geschieht.

32
Jonas Kölker

Wie wäre es mit Spreizbäume ?

Auch Chris Okasakis rein funktionale Datenstrukturen fallen mir ein.

31
starblue

Eine interessante Variante der Hash-Tabelle heißt Cuckoo Hashing . Es werden mehrere Hash-Funktionen anstelle von nur 1 verwendet, um Hash-Kollisionen zu behandeln. Kollisionen werden behoben, indem das alte Objekt aus dem durch den primären Hash angegebenen Speicherort entfernt und an einen durch eine alternative Hash-Funktion angegebenen Speicherort verschoben wird. Cuckoo Hashing ermöglicht eine effizientere Nutzung des Speicherplatzes, da Sie Ihren Auslastungsfaktor mit nur 3 Hash-Funktionen auf 91% steigern können und dennoch eine gute Zugriffszeit haben.

29
A. Levy

Ein Min-Max-Heap ist eine Variation eines Heap , die eine Warteschlange mit doppelter Priorität implementiert. Dies wird durch eine einfache Änderung der Eigenschaft heap erreicht: Ein Baum wird als min-max geordnet bezeichnet, wenn jedes Element auf geraden (ungeraden) Ebenen kleiner (größer) ist als alle Kinder und Enkelkinder. Die Ebenen sind ab 1 nummeriert.

http://internet512.chonbuk.ac.kr/datastructure/heap/img/heap8.jpg

27
marcog

Ich mag Cache Oblivious Datenstrukturen . Die Grundidee besteht darin, einen Baum in rekursiv kleineren Blöcken anzuordnen, damit Caches mit vielen verschiedenen Größen die Vorteile von Blöcken nutzen können, die bequem in sie passen. Dies führt zu einer effizienten Nutzung des Cachings in allen Bereichen, vom L1-Cache in RAM bis hin zu großen Datenmengen, die von der Festplatte gelesen werden, ohne dass die Einzelheiten der Größe einer dieser Caching-Schichten bekannt sein müssen.

26
btilly

Links geneigte rot-schwarze Bäume . Eine deutlich vereinfachte Implementierung von rot-schwarzen Bäumen von Robert Sedgewick aus dem Jahr 2008 (~ die Hälfte der zu implementierenden Codezeilen). Wenn Sie jemals Probleme mit der Implementierung eines Rot-Schwarz-Baums hatten, lesen Sie mehr über diese Variante.

Sehr ähnlich (wenn nicht identisch) zu Andersson Trees.

23
Lucas

Arbeit stehlen Warteschlange

Sperrfreie Datenstruktur zur Aufteilung der Arbeit auf mehrere Threads Implementierung einer Work Stealing Queue in C/C++?

22
Marko Tintor

Bootstrapped Skew-Binomial Heaps von Gerth Stølting Brodal und Chris Okasaki:

Trotz ihres langen Namens bieten sie auch in einer Funktionseinstellung asymptotisch optimale Heap-Operationen.

  • O(1) Größe, Vereinigung , einfügen, Minimum
  • O(log n) deleteMin

Beachten Sie, dass die Vereinigung O(1) statt O(log n) Zeit in Anspruch nimmt, im Gegensatz zu den bekannteren Heaps, die üblicherweise in Datenstruktur-Lehrbüchern behandelt werden, wie linke Heaps . Und im Gegensatz zu Fibonacci-Haufen sind diese Asymptotika im schlimmsten Fall und nicht amortisiert, selbst wenn sie beharrlich verwendet werden!

Es gibt mehrereImplementierungen in Haskell.

Sie wurden gemeinsam von Brodal und Okasaki abgeleitet, nachdem Brodal mit der gleichen Asymptotik einen imperativen Haufen aufstellte.

19
Edward KMETT
  • Kd-Trees , räumliche Datenstruktur, die (unter anderem) beim Echtzeit-Raytracing verwendet wird, hat den Nachteil, dass Dreiecke, die die verschiedenen Räume kreuzen, abgeschnitten werden müssen. Im Allgemeinen sind BVH schneller, weil sie leichter sind.
  • MX-CIF Quadtrees , speichern Sie Begrenzungsrahmen anstelle von beliebigen Punktmengen, indem Sie einen regulären Quadtree mit einem Binärbaum an den Rändern der Quads kombinieren.
  • HAMT , hierarchische Hash-Map mit Zugriffszeiten, die aufgrund der beteiligten Konstanten in der Regel O(1) Hash-Maps überschreiten.
  • Invertierter Index , in Suchmaschinenkreisen wohlbekannt, da hiermit Dokumente, die mit verschiedenen Suchbegriffen verknüpft sind, schnell abgerufen werden können.

Die meisten, wenn nicht alle, sind im NIST Dictionary of Algorithms and Data Structures dokumentiert

18
Jasper Bekkers

Nicht wirklich eine Datenstruktur; eher eine Möglichkeit, dynamisch zugewiesene Arrays zu optimieren, aber die in Emacs verwendeten Gap Buffer sind irgendwie cool.

17
kerkeslager

Fenwick Baum. Es ist eine Datenstruktur, um die Summe aller Elemente in einem Vektor zwischen zwei gegebenen Subindizes i und j zu zählen. Die triviale Lösung, bei der die Summe von Anfang an vorberechnet wird, ermöglicht keine Aktualisierung eines Elements (Sie müssen O(n) arbeiten, um Schritt zu halten).

Mit Fenwick Trees können Sie O (log n) aktualisieren und abfragen, und wie es funktioniert, ist wirklich cool und einfach. Es ist in Fenwicks Originalarbeit, die hier frei verfügbar ist, wirklich gut erklärt:

http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol24/issue3/spe884.pdf

Sein Vater, der RQM-Baum, ist auch sehr cool: Er ermöglicht es Ihnen, Informationen über das minimale Element zwischen zwei Indizes des Vektors zu speichern, und er funktioniert auch bei der Aktualisierung und Abfrage von O (log n). Ich unterrichte zuerst das RQM und dann den Fenwick Tree.

16
eordano

Van Emde-Boas-Bäume . Ich habe sogar ein C++ Implementierung davon, für bis zu 2 ^ 20 ganze Zahlen.

14
zvrba

Verschachtelte Mengen sind nützlich, um Bäume in den relationalen Datenbanken darzustellen und Abfragen auf ihnen auszuführen. Zum Beispiel enthält ActiveRecord (Ruby on Rails 'Standard-ORM) ein sehr einfaches verschachteltes Set-Plugin , was das Arbeiten mit Bäumen trivial macht.

13
esad

Eine nicht aufgerollte verknüpfte Liste ist eine Variation der verknüpften Liste, in der mehrere Elemente in jedem Knoten gespeichert sind. Dies kann die Cache-Leistung drastisch steigern und gleichzeitig den mit dem Speichern von Listenmetadaten wie Verweisen verbundenen Speicheraufwand verringern. Es ist verwandt mit dem B-Baum.

record node {
    node next       // reference to next node in list
    int numElements // number of elements in this node, up to maxElements
    array elements  // an array of numElements elements, with space allocated for maxElements elements
}
12
marcog

Sündenbockbäume. Ein klassisches Problem bei einfachen Binärbäumen besteht darin, dass sie aus dem Gleichgewicht geraten (z. B. wenn Schlüssel in aufsteigender Reihenfolge eingefügt werden.)

Ausgeglichene Binärbäume (AKA AVL-Bäume) verschwenden nach jedem Einfügen viel Zeit mit dem Ausgleichen.

Rot-Schwarz-Bäume bleiben ausgeglichen, erfordern jedoch einen zusätzlichen Speicherplatz für jeden Knoten.

Sündenböcke bleiben ausgeglichen wie rot-schwarze Bäume, benötigen jedoch keinen zusätzlichen Speicher. Dazu analysieren sie den Baum nach jedem Einfügen und nehmen geringfügige Anpassungen vor. Siehe http://en.wikipedia.org/wiki/Scapegoat_tree .

12
user20493

Es ist ziemlich domänenspezifisch, aber Half-Edge-Datenstruktur ist ziemlich ordentlich. Es bietet eine Möglichkeit zum Iterieren über Polygonnetze (Flächen und Kanten), die in Computergrafiken und Berechnungsgeometrien sehr nützlich ist.

12
mpen

2-3 Finger Trees von Hinze und Paterson sind eine großartige funktionale Datenstruktur Schweizer Taschenmesser mit großartiger Asymptotik für ein breites Spektrum von Operationen. Obwohl sie komplex sind, sind sie viel einfacher als die Imperativstrukturen von Persistenten Listen mit Verkettung durch rekursives Verlangsamen von Kaplan und Tarjan, die ihnen vorausgingen.

Sie arbeiten als verkettbare Deque mit O(1) Zugriff auf jedes Ende, O(log min(n,m)) Anhängen und bieten O(log min(n,length - n)) Indizierung mit direktem Zugriff auf eine monoidale Präfixsumme über einen beliebigen Teil der Sequenz.

Implementierungen existieren in Haskell , Coq , F # , Scala , Java , C , Clojure , C # und andere Sprachen.

Sie können sie verwenden, um Prioritätssuchwarteschlangen , Intervallkarten , Seile mit schnellem Kopfzugriff , Maps, Sets, verkettbare Sequenzen oder so ziemlich jede Struktur, in der man sie als monoidales Ergebnis ausdrücken kann über eine schnell catenable/indexable Sequenz.

Ich habe auch einige Folien , die ihre Herleitung und Verwendung beschreiben.

11
Edward KMETT

Eine weniger bekannte, aber ziemlich raffinierte Datenstruktur ist die Fenwick Tree (manchmal auch Binary Indexed Tree oder BIT genannt). Es speichert kumulative Summen und unterstützt O(log(n)) Operationen. Auch wenn kumulative Summen nicht sehr aufregend klingen, kann sie angepasst werden, um viele Probleme zu lösen, die eine sortierte/log (n) -Datenstruktur erfordern.

IMO, sein Hauptverkaufsargument ist die Leichtigkeit, mit der implementiert werden kann. Sehr nützlich bei der Lösung algorithmischer Probleme, bei denen andernfalls ein Rot-Schwarz/AVL-Baum codiert werden müsste.

10
MAK

Pairing Heaps ist eine Art Heap-Datenstruktur mit relativ einfacher Implementierung und hervorragender praktischer Amortisationsleistung.

10
Marko Tintor

XOR Linked List verwendet zwei XOR'd-Zeiger, um die Speicheranforderungen für doppelt verknüpfte Listen zu verringern. Ein bisschen dunkel, aber ordentlich!

10
yonkeltron

Ich liebe Interval Trees . Sie können eine Reihe von Intervallen (dh Start-/Endzeiten oder was auch immer) erfassen und abfragen, für welche Intervalle eine bestimmte Zeit enthalten ist oder welche Intervalle in einem bestimmten Zeitraum "aktiv" waren. Die Abfrage kann in O (log n) erfolgen und die Vorverarbeitung in O (n log n).

10
Jonathan

Splash Tables sind großartig. Sie ähneln einer normalen Hash-Tabelle, garantieren jedoch eine zeitlich konstante Suche und können eine Auslastung von 90% ohne Leistungseinbußen bewältigen. Sie sind eine Verallgemeinerung des Cuckoo Hash (auch eine großartige Datenstruktur). Sie scheinen patentiert zu sein, aber wie bei den meisten reinen Softwarepatenten würde ich mir keine Sorgen machen.

9
David Seiler

Verbesserte Hashing-Algorithmen sind sehr interessant. Lineares Hashing ist ordentlich, weil es erlaubt, einen "Bucket" in einer Hash-Tabelle gleichzeitig aufzuteilen, anstatt die gesamte Tabelle erneut aufzuwärmen. Dies ist besonders nützlich für verteilte Caches. Bei den meisten einfachen Aufteilungsrichtlinien werden jedoch alle Buckets schnell hintereinander aufgeteilt, und der Auslastungsfaktor der Tabelle schwankt ziemlich stark.

Ich denke, dass Spiral-Hashing auch wirklich ordentlich ist. Wie beim linearen Hashing wird jeweils ein Bucket aufgeteilt, und etwas weniger als die Hälfte der Datensätze im Bucket werden in denselben neuen Bucket gestellt. Es ist sehr sauber und schnell. Es kann jedoch ineffizient sein, wenn jeder "Bucket" von einer Maschine mit ähnlichen Spezifikationen gehostet wird. Um die Hardware voll auszunutzen, benötigen Sie eine Mischung aus weniger und leistungsstärkeren Maschinen.

8
erickson

Der Region Quadtree

(zitiert aus Wikipedia )

Der Regionsquadtree stellt eine Raumaufteilung in zwei Dimensionen dar, indem die Region in vier gleiche Quadranten, Subquadranten usw. zerlegt wird, wobei jeder Blattknoten Daten enthält, die einer bestimmten Subregion entsprechen. Jeder Knoten in der Struktur hat entweder genau vier untergeordnete Knoten oder keine untergeordneten Knoten (ein Blattknoten).

Quadtrees wie diese eignen sich zum Speichern von räumlichen Daten, z. Breitengrad und Längengrad oder andere Arten von Koordinaten.

Dies war bei weitem meine Lieblingsdatenstruktur im College. Es war ziemlich cool, diesen Typen zu codieren und zu sehen, wie er funktioniert. Ich kann es nur empfehlen, wenn Sie nach einem Projekt suchen, das einige Überlegungen erfordert und etwas abseits der ausgetretenen Pfade liegt. Auf jeden Fall macht es viel mehr Spaß als die Standard-BST-Derivate, die Sie normalerweise in Ihrer Datenstrukturklasse zuweisen!

Tatsächlich habe ich als Bonus die Notizen aus der Vorlesung gefunden, die zu dem Klassenprojekt geführt hat (von Virginia Tech) hier (pdf-Warnung) .

8
Andrew Whitaker

Binärentscheidungsdiagramm ist eine meiner bevorzugten Datenstrukturen, oder tatsächlich das Reduced Ordered Binary Decision Diagram (ROBDD).

Diese Art von Strukturen kann zum Beispiel verwendet werden für:

  • Darstellen von Elementmengen und Ausführen sehr schneller logischer Operationen an diesen Mengen.
  • Beliebiger boolescher Ausdruck mit der Absicht, alle Lösungen für den Ausdruck zu finden

Beachten Sie, dass viele Probleme als boolescher Ausdruck dargestellt werden können. Zum Beispiel kann die Lösung für ein Suduku als boolescher Ausdruck ausgedrückt werden. Wenn Sie eine BDD für diesen booleschen Ausdruck erstellen, erhalten Sie sofort die Lösung (en).

8
Zuu

Ich mag Treaps - für die einfache, aber effektive Idee, eine Heap-Struktur mit zufälliger Priorität über einen binären Suchbaum zu legen, um diesen auszugleichen.

7
Rafał Dowgird

Fast Compact versucht:

6
bill

Ich verwende manchmal Inversion LIsts , um Bereiche zu speichern, und sie werden oft verwendet, um Zeichenklassen in regulären Ausdrücken zu speichern. Siehe zum Beispiel http://www.ibm.com/developerworks/linux/library/l-cpinv.html

Ein weiterer Nice-Anwendungsfall betrifft gewichtete zufällige Entscheidungen. Angenommen, Sie haben eine Liste von Symbolen und zugehörigen Wahrscheinlichkeiten und möchten diese nach diesen Wahrscheinlichkeiten zufällig auswählen

 a => 0,1 
 b => 0,5 
 c => 0,4 ​​

Dann machen Sie eine laufende Summe aller Wahrscheinlichkeiten:

 (0,1, 0,6, 1,0) 

Dies ist Ihre Inversionsliste. Sie generieren eine Zufallszahl zwischen 0 und 1 und finden den Index des nächsthöheren Eintrags in der Liste. Sie können dies mit einer binären Suche tun, da diese sortiert ist. Sobald Sie den Index haben, können Sie das Symbol in der ursprünglichen Liste nachschlagen.

Wenn Sie n Symbole haben, haben Sie O(n) Vorbereitungszeit und dann O(log(n)) Zugriffszeit für jedes zufällig ausgewählte Symbol - unabhängig von die Verteilung der Gewichte.

Eine Variation von Inversionslisten verwendet negative Zahlen, um den Endpunkt von Bereichen anzugeben, wodurch es einfach ist zu zählen, wie viele Bereiche an einem bestimmten Punkt überlappen. Ein Beispiel finden Sie unter http://www.perlmonks.org/index.pl?node_id=841368 .

6
moritz

DAWG s sind eine spezielle Art von Trie, bei der ähnliche untergeordnete Bäume zu Alleinerziehenden komprimiert werden. Ich habe modifizierte DAWGs erweitert und eine raffinierte Datenstruktur namens ASSDAWG (Anagram Search Sorted DAWG) entwickelt. Dies funktioniert immer dann, wenn eine Zeichenfolge in die DAWG eingefügt wird, sie zuerst in Gruppen sortiert und dann eingefügt wird und die Blattknoten ein zusätzliche Zahl enthalten, das angibt, welche Permutationen gültig sind, wenn wir diesen Blattknoten von aus erreichen Wurzel. Das hat 2 raffinierte Vorteile:

  1. Da ich die Zeichenfolgen vor dem Einfügen sortiere und DAWGs auf natürliche Weise ähnliche Unterbäume kollabieren, erhalte ich ein hohes Maß an Komprimierung (z. B. "essen", "essen", "Tee") welche Permutationen von aet sind gültig).
  2. Die Suche nach Anagrammen einer bestimmten Zeichenfolge ist jetzt superschnell und trivial, da ein Pfad von der Wurzel zum Blatt alle gültigen Anagramme dieses Pfades am Blattknoten unter Verwendung von Permutationsnummern enthält.
6
pathikrit

Zählte unsortierte ausgeglichene Bäume.

Perfekt für Texteditor-Puffer.

http://www.chiark.greenend.org.uk/~sgtatham/algorithms/cbtree.html

6
user82238

Arne Andersson Bäume sind eine einfachere Alternative zu rot-schwarzen Bäumen, bei denen nur die richtigen Links rot sein können. Dies vereinfacht die Wartung erheblich und hält die Leistung auf dem Niveau von rot-schwarzen Bäumen. Das Originalpapier enthält ein nette und kurze Implementierung zum Einfügen und Löschen.

6
huitseeker

Fenwick-Bäume (oder binär indizierte Bäume) sind eine würdige Ergänzung zu ihrem Toolkit. Wenn Sie über ein Array von Zählern verfügen und diese ständig aktualisieren müssen, während Sie nach kumulativen Zählern fragen (wie bei der PPM-Komprimierung), führen Fenwick-Bäume alle Vorgänge in O (log n) -Zeit aus und benötigen keinen zusätzlichen Speicherplatz . Siehe auch dieses Topcoder-Tutorial für eine gute Einführung.

5

Zobrist Hashing ist eine Hash-Funktion, die im Allgemeinen zur Darstellung einer Spielbrettposition (wie im Schach) verwendet wird, aber sicherlich andere Verwendungszwecke hat. Eine nette Sache dabei ist, dass es inkrementell aktualisiert werden kann, wenn das Board aktualisiert wird.

5
Fantius

BK-Bäume oder Burkhard-Keller-Bäume ist eine baumbasierte Datenstruktur, mit der Sie schnell Übereinstimmungen mit einem String finden können.

5
Ashish

Ich mag Suffix-Baum und Arrays für die String-Verarbeitung, Skip-Listen für ausgeglichene Listen und Splay-Bäume für automatische Ausgleichsbäume

5
Antonio

Schauen Sie sich den Seitenhaufen an, den Donald Knuth präsentiert.

http://stanford-online.stanford.edu/seminars/knuth/071203-knuth-300.asx

5
4
Vaibhav Bajpai

Spreizbäume sind cool. Sie ordnen sich so neu, dass die am häufigsten abgefragten Elemente näher an die Wurzel rücken.

4
mdm

B * Baum

Es handelt sich um eine Vielzahl von B-Bäumen, mit denen auf Kosten einer teureren Einfügung effizient gesucht werden kann.

4
karlphillip

Sie können einen Min-Heap verwenden, um das minimale Element in konstanter Zeit zu finden, oder einen Max-Heap, um das maximale Element zu finden. Aber was ist, wenn Sie beide Operationen ausführen möchten? Sie können ein Min-Max verwenden, um beide Operationen in konstanter Zeit auszuführen. Es funktioniert mit der Min-Max-Reihenfolge: Wechsel zwischen Min- und Max-Heap-Vergleich zwischen aufeinander folgenden Baumebenen.

4
Firas Assaad

Ich liebe das einfache Ring-Buffer.

Bei richtiger Implementierung können Sie Ihren Speicherbedarf erheblich reduzieren, die Leistung beibehalten und manchmal sogar verbessern.

4
user97214

Gemäß den Erwähnungen von Bloom Filter sind Deletable Bloom Filter (DlBF) in gewisser Weise besser als grundlegende Zählvarianten. Siehe http://arxiv.org/abs/1005.0352

4
user201295

Eine mit 2 Stapeln implementierte Warteschlange ist ziemlich platzsparend (im Gegensatz zur Verwendung einer verknüpften Liste, die mindestens einen zusätzlichen Zeiger-/Referenz-Overhead hat).

Wie implementiert man eine Queue mit zwei Stacks?

Das hat bei mir gut funktioniert, wenn die Warteschlangen riesig sind. Wenn ich 8 Bytes für einen Zeiger speichere, bedeutet dies, dass Warteschlangen mit einer Million Einträgen etwa 8 MB RAM einsparen.

3
dhruvbird

Ternärer Suchbaum

  • Schnelle Präfixsuche (für inkrementelle Autovervollständigung usw.)
  • Partial Matching (Wenn Sie alle Wörter innerhalb des X-Hamming-Abstands einer Zeichenfolge suchen möchten)
  • Platzhaltersuchen

Ganz einfach zu implementieren.

3
st0le
3
ade

Überspringlisten sind eigentlich ganz toll: http://en.wikipedia.org/wiki/Skip_list

3
DanC89

Ich finde den FM-Index von Paolo Ferragina und Giovanni Manzini echt cool. Besonders in der Bioinformatik. Es handelt sich im Wesentlichen um einen komprimierten Volltextindex, der eine Kombination aus einem Suffix-Array und einer Burrows-Wheeler-Transformation des Referenztexts verwendet. Der Index kann durchsucht werden, ohne den gesamten Index zu dekomprimieren.

3
GWW
2
Gregable

Ich bin nicht sicher, ob diese Datenstruktur einen Namen hat, aber die vorgeschlagene tokenmap Datenstruktur für die Aufnahme in Boost ist irgendwie interessant. Es ist eine dynamisch veränderbare Karte, bei der Look-ups nicht nur O (1) sind, sondern einfache Array-Zugriffe. Ich habe das meiste Hintergrundmaterial über diese Datenstruktur geschrieben, die das grundlegende Prinzip dahinter beschreibt, wie es funktioniert.

So etwas wie eine Tokenmap wird von Betriebssystemen verwendet, um Datei- oder Ressourcenhandles Datenstrukturen zuzuordnen, die die Datei oder Ressource darstellen.

2
Daniel Trebbien

Eine richtige String-Datenstruktur. Fast jeder Programmierer entscheidet sich für die native Unterstützung, die eine Sprache für die Struktur bietet, und das ist normalerweise ineffizient (insbesondere für das Erstellen von Strings benötigen Sie eine separate Klasse oder etwas anderes).

Das Schlimmste ist, eine Zeichenfolge als Zeichenfeld in C zu behandeln und sich aus Sicherheitsgründen auf das NULL-Byte zu verlassen.

2
Rudolf Olah

Ich persönlich finde spärliche Matrixdatenstrukturen sehr interessant. http://www.netlib.org/linalg/html_templates/node90.html

Die berühmten BLAS-Bibliotheken verwenden diese. Und wenn Sie sich mit linearen Systemen befassen, die 100.000 Zeilen und Spalten enthalten, ist es wichtig, diese zu verwenden. Einige davon ähneln auch dem in der Computergrafik üblichen kompakten Raster (im Grunde genommen einem nach Eimern sortierten Raster). http://www.cs.kuleuven.be/~ares/publications/LD08CFRGRT/LD08CFRGRT.pdf

Auch in Bezug auf Computergrafiken sind MAC-Grids etwas interessant, aber nur, weil sie clever sind. http://www.seas.upenn.edu/~cis665/projects/Liquation_665_Report.pdf

2
CJJ

A Eckdatenstruktur . Aus der Zusammenfassung:

Eckstiche sind eine Technik zur Darstellung rechteckiger zweidimensionaler Objekte. Es scheint sich besonders für interaktive Bearbeitungssysteme für VLSI-Layouts zu eignen. Die Datenstruktur weist zwei wichtige Merkmale auf: Erstens wird der leere Raum explizit dargestellt; und zweitens werden rechteckige Bereiche an ihren Ecken wie eine Patchworkdecke zusammengenäht. Diese Organisation führt zu schnellen Algorithmen (lineare Zeit oder besser) zum Suchen, Erstellen, Löschen, Strecken und Verdichten. Die Algorithmen werden unter einem vereinfachten Modell von VLSI-Schaltungen vorgestellt und die Speicheranforderungen der Struktur werden diskutiert. Messungen zeigen, dass Eckstiche ungefähr dreimal so viel Speicherplatz wie die einfachstmögliche Darstellung benötigen.

2
Trey Jackson

Burrows – Wheeler-Transformation (Block-Sortierkomprimierung)

Sein wesentlicher Algorithmus für die Komprimierung. Angenommen, Sie möchten Zeilen in Textdateien komprimieren. Sie würden sagen, wenn Sie die Zeilen sortieren, verlieren Sie Informationen. BWT funktioniert jedoch so: Es reduziert die Entropie erheblich, indem es die Eingaben sortiert und ganzzahlige Indizes beibehält, um die ursprüngliche Reihenfolge wiederherzustellen.

2

Disjoint Set Forests ermöglicht schnelle Mitgliedschaftsabfragen und Gewerkschaftsoperationen und wird am bekanntesten in Kruskal's Algorithmus für minimale Spannweiten verwendet.

Das wirklich Coole ist, dass beide Operationen die Laufzeit proportional zur Inversen der Ackermann-Funktion amortisiert haben. schnellste "nicht konstante Zeitdatenstruktur.

2
hugomg

Delta-Liste/Delta-Warteschlange werden in Programmen wie Cron oder Ereignissimulatoren verwendet, um zu ermitteln, wann das nächste Ereignis ausgelöst werden soll. http://everything2.com/title/delta+listhttp://www.cs.iastate.edu/~cs554/lec_notes/delta_clock.pdf

2
ade

Eimerbrigade

Sie werden häufig in Apache verwendet. Im Grunde handelt es sich um eine verknüpfte Liste, die sich in einem Ring auf sich selbst bezieht. Ich bin nicht sicher, ob sie außerhalb von Apache- und Apache-Modulen verwendet werden, aber sie passen als coole, aber weniger bekannte Datenstruktur. Ein Bucket ist ein Container für beliebige Daten, und eine Bucket-Brigade ist eine Sammlung von Buckets. Die Idee ist, dass Sie Daten an jeder Stelle in der Struktur ändern und einfügen können möchten.

Nehmen wir an, Sie haben eine Bucket-Brigade, die ein HTML-Dokument mit einem Zeichen pro Bucket enthält. Sie möchten alle Symbole < und > in Entitäten &lt; und &gt; konvertieren. Mit der Bucket-Brigade können Sie einige zusätzliche Eimer in die Brigade einfügen, wenn Sie auf ein <- oder >-Symbol stoßen, um die für die Entität erforderlichen zusätzlichen Zeichen anzupassen. Da sich die Eimerbrigade in einem Ring befindet, können Sie sie vorwärts oder rückwärts einsetzen. Dies ist viel einfacher (in C) als die Verwendung eines einfachen Puffers.

Einige Hinweise zu Eimerbrigaden:

Apache Bucket Brigade Reference

Einführung in Eimer und Brigaden

2
John Scipione

PATRICIA - Praktischer Algorithmus zum Abrufen von alphanumerisch codierten Informationen, D. R. Morrison (1968).

Ein PATRICIA-Baum ist mit einem Trie verwandt. Das Problem bei Tries ist, dass, wenn der Schlüsselsatz spärlich ist, dh wenn die tatsächlichen Schlüssel eine kleine Teilmenge des Satzes potenzieller Schlüssel bilden, wie es sehr oft der Fall ist, viele (die meisten) internen Knoten im Trie nur haben ein Nachkomme. Dies führt dazu, dass der Trie eine hohe Raumkomplexität aufweist.

http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Tree/PATRICIA/

2
juancn

Half Edge-Datenstruktur und Winged Edge für polygonale Netze.

Nützlich für Algorithmen zur Berechnung der Geometrie.

1
habeanf

Jemand anderes hat bereits Burkhard-Keller-Bäume vorgeschlagen, aber ich dachte, ich könnte sie noch einmal erwähnen, um meine eigene Implementierung einzuschalten. :)

http://well-adjusted.de/mspace.py/index.html

Es gibt schnellere Implementierungen (siehe ActiveStates Python -Rezepte oder Implementierungen in anderen Sprachen), aber ich denke/hoffe, mein Code hilft, diese Datenstrukturen zu verstehen.

Übrigens können sowohl BK- als auch VP-Bäume für viel mehr als die Suche nach ähnlichen Zeichenfolgen verwendet werden. Sie können Ähnlichkeitssuchen für beliebige Objekte durchführen, sofern Sie eine Abstandsfunktion haben, die einige Bedingungen erfüllt (Positivität, Symmetrie, Dreieckungleichheit).

1
Jochen
  • Binärentscheidungsdiagramm (meine Lieblingsdatenstruktur, gut für die Darstellung und Lösung von Booleschen Gleichungen. Wirksam für viele Dinge)
  • Heaps (ein Baum, in dem das übergeordnete Element eines Knotens immer eine gewisse Beziehung zu den untergeordneten Elementen des Knotens beibehält, z. B. ist das übergeordnete Element eines Knotens immer größer als jedes untergeordnete Element (max-heap))
  • Prioritätswarteschlangen (eigentlich nur Min-Heaps und Max-Heaps, gut, um die Reihenfolge vieler Elemente dort aufrechtzuerhalten, wobei beispielsweise der Gegenstand mit dem höchsten Wert zuerst entfernt werden soll)
  • Hash-Tabellen (mit allen Arten von Suchstrategien und Behandlung von Bucket-Überläufen)
  • Ausgewogene binäre Suchbäume (Jeder von ihnen hat seine eigenen Vorteile)
    • RB-Bäume (insgesamt gut, beim Einfügen, Nachschlagen, Entfernen und Iterieren in einer geordneten Weise)
    • Avl-Bäume (schneller zum Nachschlagen als RB, aber ansonsten sehr ähnlich zu RB)
    • Splay-Bäume (schneller zum Nachschlagen, wenn kürzlich verwendete Knoten wahrscheinlich wiederverwendet werden)
    • Fusionsbaum (Nutzung der schnellen Multiplikation für noch bessere Suchzeiten)
    • B + Trees (Wird für die Indizierung in Datenbanken und Dateisystemen verwendet und ist sehr effizient, wenn die Wartezeit für das Lesen/Schreiben vom/zum Index erheblich ist.).
  • Raumindizes (Hervorragend geeignet, um abzufragen, ob Punkte/Kreise/Rechtecke/Linien/Würfel nahe beieinander liegen oder ineinander enthalten sind.)
    • BSP-Baum
    • Quadtree
    • Octree
    • Range-Baum
    • Viele ähnliche, aber leicht unterschiedliche Bäume und unterschiedliche Dimensionen
  • Intervallbäume (gute Suche nach überlappenden Intervallen, linear)
  • Grafiken
    • adjazenzliste (im Grunde eine Liste von Kanten)
    • adjazenzmatrix (eine Tabelle, die gerichtete Kanten eines Diagramms mit einem einzelnen Bit pro Kante darstellt. Sehr schnell für das Durchlaufen des Diagramms)

Dies sind die, an die ich denken kann. Es gibt noch mehr auf Wikipedia über Datenstrukturen

1
Zuu

Ich hatte vorher viel Glück mit WPL Trees . Eine Baumvariante, die die gewichtete Pfadlänge der Zweige minimiert. Die Gewichtung wird durch den Knotenzugriff bestimmt, sodass häufig verwendete Knoten näher an den Stamm migrieren. Ich bin mir nicht sicher, wie sie mit Spreizbäumen verglichen werden, da ich diese noch nie verwendet habe.

1
TMN

Ich denke Cycle Sort ist ein ziemlich ordentlicher Sortieralgorithmus.

Es ist ein Sortieralgorithmus, der verwendet wird, um die Gesamtzahl der Schreibvorgänge zu minimieren. Dies ist besonders nützlich, wenn Sie mit einem Flash-Speicher arbeiten, dessen Lebensdauer proportional zur Anzahl der Schreibvorgänge ist. Hier ist der Wikipedia-Artikel , aber ich empfehle, zum ersten Link zu gehen. (Schöne Bilder!)

1
jyt

Binomial Heap 's haben viele interessante Eigenschaften, von denen die nützlichste das Zusammenführen ist.

1
DShook

Umgebungsverfolgung von rekursiven Strukturen.

Compiler verwenden eine Struktur, die rekursiv ist, aber nicht wie ein Baum. Innere Bereiche haben einen Zeiger auf einen umschließenden Bereich, sodass die Verschachtelung von innen nach außen erfolgt. Das Überprüfen, ob sich eine Variable im Gültigkeitsbereich befindet, ist ein rekursiver Aufruf vom inneren Gültigkeitsbereich zum umschließenden Gültigkeitsbereich.

public class Env
{    
    HashMap<String, Object> map;
    Env                     outer;

    Env()
    {
        outer = null;
        map = new HashMap();
    }

    Env(Env o)
    {
        outer = o;
        map = new HashMap();
    }

    void put(String key, Object value)
    {
        map.put(key, value);
    }

    Object get(String key)
    {
        if (map.containsKey(key))
        {
            return map.get(key);
        }
        if (outer != null)
        {
            return outer.get(key);
        }
        return null;
    }

    Env Push()
    {
        return new Env(this);
    }

    Env pop()
    {
        return outer;
    }
}

Ich bin mir nicht sicher, ob diese Struktur überhaupt einen Namen hat. Ich nenne es eine Inside-Out-Liste.

1
Kelly S. French

Es gibt eine clevere Datenstruktur, die Arrays verwendet, um die Daten der Elemente zu speichern, aber die Arrays sind in einer Linked-List/Array miteinander verknüpft.

Dies hat den Vorteil, dass die Iteration über die Elemente sehr schnell ist (schneller als bei einem reinen Ansatz mit verknüpften Listen) und die Kosten für das Verschieben der Arrays mit den Elementen im Speicher und/oder die (De-) Zuordnung minimal sind. (Aus diesem Grund ist diese Datenstruktur nützlich für Simulationen).

Ich weiß es von hier:

http://software.intel.com/en-us/blogs/2010/03/26/linked-list-verses-array/

"... und dass ein zusätzliches Array zugewiesen und mit der Zellenliste der Partikelarrays verknüpft wird. Dies ähnelt in gewisser Hinsicht der Implementierung des gleichzeitigen Containers durch TBB." )

1
Quonux

rechtwinklige Dreiecksnetzwerke (RTINs)

Schön einfache Möglichkeit, ein Netz adaptiv zu unterteilen. Split- und Merge-Vorgänge bestehen nur aus wenigen Codezeilen.

0
Jon Harrop

Ich bin auf eine andere Datenstruktur gestoßen Cartesian Tree , als ich etwas über Algorithmen im Zusammenhang mit RMQ und LCA las. In einem kartesischen Baum ist der niedrigste gemeinsame Vorfahr zwischen zwei Knoten der Mindestknoten zwischen ihnen. Es ist nützlich, ein RMQ-Problem in eine Ökobilanz umzuwandeln.

0
jscoot