2016-04-15 2 views
0

Sagen wir, dass ich ein Wörterbuch (in .NET) mit Schlüsseln von 1 bis 100 habe. Ich kenne von meinen historischen Daten, dass 99% der Zeit ich Greifen Sie auf dieses Wörterbuch zu, um die Daten für die Schlüssel 5, 37, 88 abzurufen. Gibt es eine Möglichkeit, dieses Diktat so zu organisieren, dass es sehr schnell mit diesen 3 Schlüsseln ist, sogar auf Kosten von mehr Zeitverschwendung bei der Suche nach den verbleibenden 97 Schlüssel? Oder gibt es vielleicht eine andere Datenstruktur, die dieses Wissen nutzen könnte, um die durchschnittliche Zugriffszeit auf Daten zu verbessern?Wie man eine Wörterbuchleistung mit Geschäftslogikwissen "helfe"

Antwort

0

In einer vernünftigen Implementierung eines Wörterbuchs werden die Kosten einer Suche von den Kosten eines Speicherzugriffs dominiert. Ihre Hardware wird dies für Sie optimieren und die am häufigsten verwendeten Elemente in den schnellsten Cache-Ebenen belassen. 100 Gegenstände passen in Ihren schnellsten Cache, es sei denn, Sie haben einen winzigen Computer.

Das heißt, wenn Sie eine Hash-Tabelle mit separaten Verkettung verwenden, können Sie diese Elemente an den Anfang ihrer Ketten verschieben. Dies stellt sicher, dass das Nachschlagen dieser Elemente O (1) Worst Case garantiert wird, während für mindestens ein Element in Ihrem Wörterbuch die Suche mit hoher Wahrscheinlichkeit O (log n/log log n) ist.

Natürlich, wenn Sie nur 100 Schlüssel haben, wird die Verwendung einer Hash-Tabelle anstelle eines Wörterbuchs sicherstellen, dass jeder Schlüssel O (1) Worst-Case-Zugriff hat.

0

Sie könnten einen kleinen Cache vor dem Wörterbuch verwenden, der schneller sein könnte. Wenn Sie beispielsweise wissen, dass die meisten Ihrer Zugang sind für Artikel 3, 37 und 88, dann könnten Sie haben:

private Dictionary<int, MyDataType> TheDictionary; 
private KeyValuePair<int, MyDataType>[] quickLookup; 

void InitializeDictionary() 
{ 
    TheDictionary = new Dictionary<int, MyDataType>(); 
    // here, initialize the dictionary with the data. 

    // Now, set up the cache 
    quickLookup = new KeyValuePair<int, MyDataType>[] 
    { 
     new KeyValuePair(3, TheDictionary[3]), 
     new KeyValuePair(37, TheDictionary[37]), 
     new KeyValuePair(88, TheDictionary[88]) 
    }; 

Nun, wenn Sie für einen Artikel suchen möchten, müssen Sie zunächst den Cache überprüfen:

bool TryDictionaryLookup(int key, out MyDataType data) 
{ 
    foreach (var kvp in quickLookup) 
    { 
     if (kvp.key == key) 
     { 
      data = kvp.Value; 
      return true; 
     } 
    } 

    // didn't find it. Check the dictionary. 
    return TheDictionary.TryGetValue(key, out data); 
} 

Dies sollten Sie boost eine kleine Leistung geben, wenn Sie den Cache nur drei Elemente ist. Wenn Sie jedoch mehr als fünf oder sechs Elemente erhalten, wird es wahrscheinlich schlechter abschneiden als das direkte Wörterbuch. Sie müssen einige Zeitpunkte festlegen, um festzustellen, wo der Sweet Spot ist.

Beachten Sie auch, dass, wenn Sie wirklich in diese Art von Mikro-Optimierung sind, haben Sie wahrscheinlich die foreach mit einer for Schleife ersetzen sollen:

for (int i = 0; i < quickLookup.Length) 
{ 
    if (quickLookup[i].Key == key) 
    ... 
    ... 

Das wird den Aufwand für die Erstellung des enumerator beseitigen.

Der Grund, warum diese Technik eine Leistungssteigerung bieten sollte, ist, dass für den Zugriff auf das Wörterbuch ein Hashwert vom Schlüssel berechnet werden muss. Während dies eine schnelle Operation ist, ist es immer noch mehr Aufwand als ein paar Array-Zugriffe. Auch hier sollten Sie dies gründlich mit repräsentativen Daten testen und profilieren, bevor Sie es in Produktion nehmen.

Der C# -Compiler verwendet (zumindest verwendet; ich habe seit einer Weile nicht mehr überprüft) etwas ähnliches beim Generieren von Code für switch Anweisungen. Wenn die switch enthält weniger als einige Zahl Fälle (ich denke, es war sechs, das letzte Mal, wenn ich überprüft), dann generiert der Compiler eine Reihe von if/else Aussagen. Für sechs oder mehr Elemente generiert es ein Wörterbuch mit Schlüsseln und Verzweigungsorten und Code, um den Fallwert in einem Wörterbuch nachzuschlagen und zu dem relevanten Code zu verzweigen.