Es gibt mehrere potenziell nicht-O (1) Teile für ein Wörterbuch.
Die erste erzeugt einen Hash-Code. Wenn Ihre Strings lang sind, müssen Sie jedes Mal einen Hash der Zeichenfolge generieren, wenn Sie sie als Schlüssel in Ihrem Wörterbuch verwenden. Das Wörterbuch speichert die Hashes der vorhandenen Schlüssel, so dass Sie sich keine Gedanken darüber machen müssen, nur was Sie übergeben. Wenn die Zeichenfolgen kurz sind, sollte Hashing schnell sein. Lange Strings brauchen wahrscheinlich länger zum Hash-Vorgang als ein String-Vergleich. Hashing wirkt sich sowohl auf Lese- als auch auf Schreibvorgänge aus.
Der nächste nicht konstante Teil eines Wörterbuchs ist, wenn Sie Hash-Kollisionen haben. Sie speichert intern eine verknüpfte Liste von Werten mit demselben Hash-Bucket und muss den Schlüssel mit jedem Element in diesem Bucket vergleichen und vergleichen, wenn Hash-Kollisionen auftreten. Da Sie Strings verwenden und sehr viel Mühe darauf verwenden, eine gute String-Hashing-Funktion zu entwickeln, sollte dies kein allzu großes Problem darstellen. Hash-Kollisionen verlangsamen sowohl Lese- als auch Schreibvorgänge.
Der letzte nicht konstante Teil ist nur während des Schreibvorgangs. Wenn der interne Speicher nicht mehr ausreicht, muss er die gesamte Hash-Tabelle intern neu berechnen. Dies ist immer noch viel schneller als Array-Inserts (wie eine Liste <> tun würde). Wenn Sie nur ein paar hundert Dinge haben, wird Sie das bestimmt nicht beeinflussen.
Eine Liste auf der anderen Seite wird einen Durchschnitt von N/2 Kopien für jede Einfügung und log2 (N) für jede Suche benötigen. Wenn die Zeichenfolgen nicht alle ähnliche Präfixe haben, werden die einzelnen Vergleiche viel schneller als das Wörterbuch sein, aber es wird viel mehr von ihnen geben.
Also, wenn Ihre Strings ziemlich lang sind, Hashing ineffizient zu machen, wird ein Wörterbuch Ihnen bessere Leistung geben.
Wenn Sie etwas über die Art Ihrer Zeichenfolgen wissen, können Sie eine spezifischere Datenstruktur schreiben, die für Ihr Szenario optimiert ist. Wenn ich zum Beispiel wüsste, dass alle Strings mit einem ASCII-Großbuchstaben beginnen und jeder zwischen 5 und 10 Zeichen lang ist, könnte ich ein Array von 26 Arrays erstellen, eines für jeden Buchstaben, und dann enthält jedes dieser Arrays 6 Listen , eine für jede Saitenlänge. Etwas wie folgt aus:
List<string>[][] lists = new List<string>[26][6];
foreach (string s in keys)
{
var list = lists[s[0] - 'A'][s.Length - 5];
if (list == null)
{
lists[s[0] - 'A'][s.Length] = list = new List<string>();
}
int ix = list.BinarySearch(s);
if (ix < 0)
{
list.Insert(~ix, s);
}
}
Dies ist die Art von Sache, die Sie tun, wenn Sie sehr spezifische Informationen über haben, welche Art von Daten, die Sie zu tun haben. Wenn Sie keine Vermutungen anstellen können, ist die Verwendung eines Wörterbuchs wahrscheinlich die beste Wahl.
Sie könnten auch in Betracht ziehen, OrderedDictionary zu verwenden, wenn Sie binäre Suchroute gehen, glaube ich, dass es intern einen binären Suchbaum verwendet. https://msdn.microsoft.com/en-us/library/system.collections.specialized.ordereddictionary%28v=vs.110%29.aspx
https://ericlippert.com/2012/12/17/performance-rant/ – Blorgbeard
@ Blorgbeard Ich habe die Idee dieser Bemerkung. Das Problem ist, ich weiß nicht, wie man den Unterschied in der Leistung der beiden korrekt misst. Ich hoffte auf einen Hinweis, basierend auf tiefgreifenden Kenntnissen der Interna unter der Haube, solange diese API-Gruppen alt sind und bereits tief von jemandem erforscht werden konnten. –