it-swarm.com.de

.NET-Datenstrukturen: ArrayList, List, HashTable, Dictionary, SortedList, SortedDictionary - Geschwindigkeit, Speicher und wann jeweils?

.NET hat viele komplexe Datenstrukturen. Leider sind einige davon ziemlich ähnlich, und ich bin mir nicht immer sicher, wann ich eines und wann ich ein anderes verwenden soll. Die meisten meiner C # - und Visual Basic-Bücher behandeln sie bis zu einem gewissen Grad, aber sie gehen nie wirklich ins Detail.

Was ist der Unterschied zwischen Array, ArrayList, List, Hashtable, Dictionary, SortedList und SortedDictionary?

Welche sind aufzählbar (IList - kann foreach-Schleifen ausführen)? Welche verwenden Schlüssel/Wert-Paare (IDict)?

Was ist mit dem Speicherbedarf? Einfügegeschwindigkeit? Abrufgeschwindigkeit?

Gibt es noch weitere erwähnenswerte Datenstrukturen?

Ich bin immer noch auf der Suche nach weiteren Details zur Speichernutzung und Geschwindigkeit (Big-O-Notation).

209
Pretzel

Aus meinem Kopf:

  • Array * - repräsentiert ein altmodisches Speicherarray - eine Art Alias ​​für ein normales type[] Array. Kann aufzählen. Kann nicht automatisch wachsen. Ich würde davon ausgehen, dass die Einfüge- und Wiederauffindungsgeschwindigkeit sehr schnell ist.

  • ArrayList - automatisch wachsendes Array. Fügt mehr Overhead hinzu. Kann enum., Wahrscheinlich langsamer als ein normales Array, aber immer noch ziemlich schnell. Diese werden häufig in .NET verwendet

  • List - einer meiner Favoriten - kann mit Generika verwendet werden, sodass Sie ein stark typisiertes Array haben können, z. List<string>. Ansonsten verhält es sich sehr ähnlich wie ArrayList

  • Hashtable - einfache alte Hashtabelle. O(1) bis O(n) Worst Case. Kann die Eigenschaften value und keys auflisten und Schlüssel/Wert-Paare ausführen

  • Dictionary - wie oben, nur stark typisiert über Generika wie Dictionary<string, string>

  • SortedList - eine sortierte generische Liste. Verlangsamt beim Einfügen, da herausgefunden werden muss, wo die Dinge abgelegt werden sollen. Kann enum., Wahrscheinlich das gleiche beim Abrufen, da es nicht zurückgreifen muss, aber das Löschen ist langsamer als eine einfache alte Liste.

Ich neige dazu, die ganze Zeit List und Dictionary zu verwenden - sobald Sie anfangen, sie zu verwenden, die stark mit Generika getippt sind, ist es wirklich schwierig, zu den Standard-Nicht-Generika zurückzukehren.

Es gibt auch viele andere Datenstrukturen - es gibt KeyValuePair, mit denen Sie einige interessante Dinge erledigen können, es gibt ein SortedDictionary, das ebenfalls nützlich sein kann.

148
Sam Schutte

Wenn möglich, verwenden Sie Generika. Dies beinhaltet:

  • Liste anstelle von ArrayList
  • Wörterbuch anstelle von HashTable
28
Adam Tegen

Zunächst implementieren alle Auflistungen in .NET IEnumerable.

Zweitens sind viele Sammlungen Duplikate, da Generika in Version 2.0 des Frameworks hinzugefügt wurden.

Also, obwohl die generischen Sammlungen wahrscheinlich Funktionen hinzufügen, zum größten Teil:

  • List ist eine generische Implementierung von ArrayList.
  • Dictionary ist eine generische Implementierung von Hashtable

Arrays sind eine Sammlung mit fester Größe, mit der Sie den an einem bestimmten Index gespeicherten Wert ändern können.

SortedDictionary ist ein IDictionary, das anhand der Schlüssel sortiert wird. SortedList ist ein IDictionary, das basierend auf einem erforderlichen IComparer sortiert wird.

Die IDictionary-Implementierungen (die KeyValuePairs unterstützen) lauten also: * Hashtable * Dictionary * SortedList * SortedDictionary

Eine andere Sammlung, die in .NET 3.5 hinzugefügt wurde, ist das Hashset. Es ist eine Sammlung, die Mengenoperationen unterstützt.

Außerdem ist LinkedList eine Standardimplementierung für verknüpfte Listen (List ist eine Array-Liste zum schnelleren Abrufen).

24
Abe Heidebrecht

Ein gutes Spickzettel Erwähnung der Komplexität von Datenstrukturen, Algorithmen usw.

21
Krishna

Hier einige allgemeine Tipps für Sie:

  • Sie können foreach für Typen verwenden, die IEnumerable implementieren. IList ist im Wesentlichen ein IEnumberable mit den Eigenschaften Count und Item (Zugriff auf Elemente mit einem auf Null basierenden Index). IDictionary bedeutet andererseits, dass Sie über einen beliebigen Hash-Index auf Elemente zugreifen können.

  • Array, ArrayList und List implementieren alle IList. Dictionary, SortedDictionary und Hashtable implementieren IDictionary.

  • Wenn Sie .NET 2.0 oder höher verwenden, wird empfohlen, generische Gegenstücke der genannten Typen zu verwenden.

  • Informationen zur zeitlichen und räumlichen Komplexität verschiedener Operationen für diese Typen finden Sie in der Dokumentation.

  • .NET Datenstrukturen sind in System.Collections Namespace. Es gibt Typbibliotheken wie PowerCollections , die zusätzliche Datenstrukturen bieten.

  • Informationen zu Datenstrukturen finden Sie in Ressourcen wie CLRS .

18
blackwing

.NET Datenstrukturen:

Mehr zum Gespräch darüber, warum ArrayList und List sich tatsächlich unterscheiden

Arrays

Wie ein Benutzer angibt, sind Arrays die "Old School" -Sammlung (ja, Arrays werden als Sammlung betrachtet, obwohl sie nicht Teil von System.Collections Sind). Aber was ist "alte Schule" bei Arrays im Vergleich zu anderen Sammlungen, d. H. Denjenigen, die Sie in Ihrem Titel aufgeführt haben (hier ArrayList und List (Of T))? Beginnen wir mit den Grundlagen, indem wir uns Arrays ansehen.

Zu Beginn sind Arrays in Microsoft .NET "Mechanismen, mit denen Sie mehrere [logisch verwandte] Elemente als eine einzige Sammlung behandeln können" (siehe verknüpften Artikel). Was bedeutet das? Arrays speichern einzelne Mitglieder (Elemente) nacheinander mit einer Startadresse im Speicher. Mithilfe des Arrays können wir einfach auf die sequentiell gespeicherten Elemente zugreifen, die an dieser Adresse beginnen.

Darüber hinaus und im Gegensatz zur Programmierung von 101 gängigen Konzepten können Arrays sehr komplex sein:

Arrays können eindimensional, mehrdimensional oder gevögelt sein (gezackte Arrays, über die es sich zu lesen lohnt). Arrays selbst sind nicht dynamisch: Einmal initialisiert, reserviert ein Array von n Größe genug Platz, um n Anzahl von Objekten aufzunehmen. Die Anzahl der Elemente im Array kann nicht vergrößert oder verkleinert werden. Dim _array As Int32() = New Int32(100) reserviert genügend Speicherplatz im Speicherblock für das Array, um 100 Int32-Objekte vom primitiven Typ zu enthalten (in diesem Fall wird das Array so initialisiert, dass es Nullen enthält). Die Adresse dieses Blocks wird an _array Zurückgegeben.

Gemäß dem Artikel erfordert Common Language Specification (CLS), dass alle Arrays auf Null basieren. Arrays in .NET unterstützen Arrays, die nicht auf Null basieren. Dies ist jedoch weniger verbreitet. Aufgrund der "Gemeinsamkeit" von nullbasierten Arrays hat Microsoft viel Zeit darauf verwendet , ihre Leistung zu optimieren ; Daher sind eindimensionale, nullbasierte (SZs) Arrays "speziell" - und wirklich die beste Implementierung eines Arrays (im Gegensatz zu mehrdimensionalen, usw.) -, da SZs über spezielle Anweisungen für die Zwischensprache verfügen, mit denen sie bearbeitet werden können.

Arrays werden immer als Referenz übergeben (als Speicheradresse) - ein wichtiger Teil des zu erfassenden Array-Puzzles. Während sie die Begrenzungsüberprüfung durchführen (was einen Fehler auslöst), kann die Begrenzungsüberprüfung auch für Arrays deaktiviert werden.

Auch hier besteht das größte Hindernis für Arrays darin, dass sie nicht in der Größe verändert werden können. Sie haben eine "feste" Kapazität. Einführung von ArrayList und List (Of T) in unsere Geschichte:

ArrayList - nicht generische Liste

Die ArrayList (zusammen mit List(Of T) - obwohl es hier einige kritische Unterschiede gibt, die später erklärt werden) - wird vielleicht am besten als die nächste Ergänzung zu Sammlungen angesehen (im weiteren Sinne). . ArrayList erbt von der Schnittstelle IList (ein Nachkomme von 'ICollection'). ArrayLists selbst sind mfangreicher - und erfordern mehr Overhead - als Listen.

IList ermöglicht der Implementierung, ArrayLists als Listen mit fester Größe (wie Arrays) zu behandeln. Über die durch ArrayLists hinzugefügte zusätzliche Funktionalität hinaus bietet die Verwendung von ArrayLists mit fester Größe jedoch keine wirklichen Vorteile, da ArrayLists (gegenüber Arrays) in diesem Fall deutlich langsamer sind.

Aus meiner Sicht können ArrayLists nicht gezackt werden: "Die Verwendung mehrdimensionaler Arrays als Elemente ... wird nicht unterstützt". Wieder ein Nagel im Sarg von ArrayLists. ArrayLists sind auch nicht "typisiert" - was bedeutet, dass eine ArrayList unter allem einfach ein dynamisches Array von Objekten ist: Object[]. Dies erfordert viel Boxing (implizit) und Unboxing (explizit), wenn ArrayLists implementiert werden, was wiederum zu ihrem Overhead beiträgt.

Unbegründeter Gedanke: Ich denke, ich erinnere mich, dass ich entweder gelesen oder von einem meiner Professoren gehört habe, dass ArrayLists eine Art Bastard-Konzeptkind des Versuchs sind, von Arrays zu Kollektionen vom Typ Liste zu wechseln, das heißt, als ich einmal großartig war Verbesserung der Arrays, sie sind nicht mehr die beste Option, da die Kollektionen weiterentwickelt wurden

List (Of T): Was ArrayList wurde (und werden sollte)

Der Unterschied in der Speichernutzung ist signifikant genug, damit eine List (Of Int32) 56% weniger Speicher verbraucht als eine ArrayList, die denselben primitiven Typ enthält (8 MB im Vergleich zu 19 MB in der verknüpften Demonstration des oben genannten Gentlemans: linked hier ) - obwohl dies ein von der 64-Bit-Maschine zusammengesetztes Ergebnis ist. Dieser Unterschied zeigt wirklich zwei Dinge: Erstens (1) ist ein Int32-Objekt (ArrayList) mit Box viel größer als ein Int32-Primitiv (List); In der zweiten (2) ist der Unterschied aufgrund der Funktionsweise einer 64-Bit-Maschine exponentiell.

Also, was ist der Unterschied und was ist ein List (Of T) ? MSDN definiert eine List(Of T) als "... eine stark typisierte Liste von Objekten, auf die durch einen Index zugegriffen werden kann." Die Wichtigkeit hierbei ist das "stark typisierte" Bit: Eine Liste (von T) "erkennt" Typen und speichert die Objekte als Typ. Ein Int32 Wird also als Int32 Und nicht als Object -Typ gespeichert. Dies beseitigt die Probleme, die durch Boxen und Unboxing verursacht werden.

MSDN gibt an, dass dieser Unterschied nur beim Speichern von primitiven Typen und nicht von Referenztypen zum Tragen kommt. Auch der Unterschied tritt tatsächlich in großem Maßstab auf: über 500 Elemente. Interessanter ist, dass in der MSDN-Dokumentation steht: "Es ist zu Ihrem Vorteil, die typspezifische Implementierung der List (Of T) -Klasse anstelle der ArrayList-Klasse zu verwenden."

Grundsätzlich ist List (Of T) ArrayList, aber besser. Es ist das "generische Äquivalent" von ArrayList. Wie bei ArrayList ist es nicht garantiert, dass es sortiert wird, bis es sortiert ist (siehe Abbildung). List (Of T) hat auch einige zusätzliche Funktionen.

7
Thomas

Ich sympathisiere mit der Frage - auch ich fand (finde?) Die Wahl verwirrend, also habe ich wissenschaftlich untersucht, welche Datenstruktur die schnellste ist (ich habe den Test mit VB durchgeführt, aber ich stelle mir vor, dass C # gleich wäre, da beide Sprachen das Gleiche auf CLR-Ebene tun). Sie sehen einige von mir hier durchgeführte Benchmarking-Ergebnisse (es wird auch diskutiert, welcher Datentyp unter welchen Umständen am besten zu verwenden ist).

5
Andy Brown

Die generischen Auflistungen erzielen eine bessere Leistung als ihre nicht generischen Gegenstücke, insbesondere wenn viele Elemente durchlaufen werden. Dies liegt daran, dass das Ein- und Auspacken nicht mehr erfolgt.

3
Russ Cam

Hashtables/Dictionaries sind O(1) Leistung, was bedeutet, dass Leistung keine Funktion der Größe ist. Das ist wichtig zu wissen.

BEARBEITEN: In der Praxis beträgt die durchschnittliche Zeitkomplexität für Hashtable/Dictionary <> Lookups O (1).

3
Chris

Sie sind ziemlich gut in Intellisense geschrieben. Geben Sie einfach System.Collections. oder System.Collections.Generics (bevorzugt) ein und Sie erhalten eine Liste und eine kurze Beschreibung der verfügbaren Funktionen.

3
Joel Coehoorn

Ein wichtiger Hinweis zu Hashtable vs Dictionary für die systematische Hochfrequenz-Handelstechnik: Thread Safety Issue

Hashtable ist threadsicher für die Verwendung durch mehrere Threads. Öffentliche statische Dictionary-Mitglieder sind threadsicher, aber es kann nicht garantiert werden, dass dies für Instanzmitglieder der Fall ist.

Daher bleibt Hashtable in dieser Hinsicht die 'Standard'-Wahl.

2
Rob

Beliebteste C # -Datenstrukturen und -Sammlungen

  • Array
  • ArrayList
  • Liste
  • LinkedList
  • Wörterbuch
  • HashSet
  • Stapel
  • Warteschlange
  • SortedList

C # .NET verfügt über viele verschiedene Datenstrukturen. Eine der häufigsten ist beispielsweise ein Array. C # enthält jedoch wesentlich mehr grundlegende Datenstrukturen. Die Auswahl der richtigen Datenstruktur ist Teil des Schreibens eines gut strukturierten und effizienten Programms.

In diesem Artikel gehe ich auf die integrierten C # -Datenstrukturen ein, einschließlich der neuen, die in C # .NET 3.5 eingeführt wurden. Beachten Sie, dass viele dieser Datenstrukturen für andere Programmiersprachen gelten.

Array

Die vielleicht einfachste und gebräuchlichste Datenstruktur ist das Array. Ein C # -Array ist im Grunde eine Liste von Objekten. Seine bestimmenden Merkmale sind, dass alle Objekte (in den meisten Fällen) vom gleichen Typ sind und es eine bestimmte Anzahl von ihnen gibt. Die Art eines Arrays ermöglicht einen sehr schnellen Zugriff auf Elemente basierend auf ihrer Position in der Liste (auch als Index bezeichnet). Ein C # -Array ist folgendermaßen definiert:

[object type][] myArray = new [object type][number of elements]

Einige Beispiele:

 int[] myIntArray = new int[5];
 int[] myIntArray2 = { 0, 1, 2, 3, 4 };

Wie Sie dem obigen Beispiel entnehmen können, kann ein Array ohne Elemente oder aus einer Reihe vorhandener Werte initialisiert werden. Das Einfügen von Werten in ein Array ist einfach, solange sie passen. Der Vorgang wird kostspielig, wenn mehr Elemente als die Größe des Arrays vorhanden sind. Zu diesem Zeitpunkt muss das Array erweitert werden. Dies dauert länger, da alle vorhandenen Elemente in das neue, größere Array kopiert werden müssen.

ArrayList

Die C # -Datenstruktur ArrayList ist ein dynamisches Array. Dies bedeutet, dass eine ArrayList eine beliebige Anzahl von Objekten und einen beliebigen Typ haben kann. Diese Datenstruktur wurde entwickelt, um das Hinzufügen neuer Elemente zu einem Array zu vereinfachen. Unter der Haube ist eine ArrayList ein Array, dessen Größe jedes Mal verdoppelt wird, wenn der Speicherplatz knapp wird. Das Verdoppeln der Größe des internen Arrays ist eine sehr effektive Strategie, die auf lange Sicht die Anzahl der Elementkopien reduziert. Wir werden hier nicht auf den Beweis dafür eingehen. Die Datenstruktur ist sehr einfach zu bedienen:

    ArrayList myArrayList = new ArrayList();
    myArrayList.Add(56);
    myArrayList.Add("String");
    myArrayList.Add(new Form());

Der Nachteil der ArrayList-Datenstruktur ist, dass die abgerufenen Werte wieder in ihren ursprünglichen Typ umgewandelt werden müssen:

int arrayListValue = (int)myArrayList[0]

Quellen und weitere Informationen finden Sie hier :

1
leonidaa

Eigentlich denke ich, dass MSDN dazu beiträgt, all diese Fragen ziemlich gut zu beantworten. Suchen Sie einfach nach .NET-Sammlungen.

1
Scott

Es gibt subtile und weniger subtile Unterschiede zwischen generischen und nicht generischen Sammlungen. Sie verwenden lediglich unterschiedliche zugrunde liegende Datenstrukturen. Zum Beispiel garantiert Hashtable, dass ein Schreiber viele Leser ohne Synchronisierung hat. Wörterbuch nicht.

1
Ilya Ryzhenkov