2009-06-01 21 views
207

Esiste una reale differenza pratica tra uno SortedList<TKey,TValue> e uno SortedDictionary<TKey,TValue>? Ci sono circostanze in cui si utilizzerebbe specificatamente l'una e non l'altra?Qual è la differenza tra SortedList e SortedDictionary?

+0

Correlato: [Quando utilizzare un SortedList o SortedDictionary] (http://stackoverflow.com/questions/1376965/when-to-use-a-sortedlisttkey-tvalue-over-a-sorteddictionarytkey-tvalue) – Liam

+9

I sono confuso Perché SortedList ha due parametri di tipo 'SortedList ' piuttosto che uno 'SortedList '? Perché non implementa 'IList '? –

+3

@ColonelPanic perché la funzione SortedList è una mappa, non una raccolta lineare. Non lasciare che il nome ti inganni. Proprio come un dizionario, si passa una chiave, si ottiene un valore indietro. Mentre il dizionario non è ordinato, SortedList viene ordinato nel suo ordine ordinato naturale. – nawfal

risposta

244

Sì, le loro caratteristiche di prestazione differiscono in modo significativo. Probabilmente sarebbe meglio chiamarli SortedList e SortedTree in quanto ciò rispecchia l'implementazione più da vicino.

Consultare i documenti MSDN per ognuno di essi (SortedList, SortedDictionary) per i dettagli delle prestazioni per diverse operazioni in diversi situtations. Ecco un bel riassunto (dalle SortedDictionary docs):

Il SortedDictionary<TKey, TValue> generica classe è un albero binario di ricerca con O (log n) di recupero, dove n è il numero di elementi nel dizionario. In questo è simile alla classe generica . Le due classi hanno modelli di oggetti simili ed entrambi hanno il recupero di O (log n) . Dove i due classi differiscono è in uso la memoria e la velocità di inserimento e la rimozione:

  • SortedList<TKey, TValue> utilizza meno memoria di SortedDictionary<TKey, TValue>.

  • SortedDictionary<TKey, TValue> ha inserimento rapido e rimozione operazioni per dati non ordinati, O (log n) al contrario di O (n) per SortedList<TKey, TValue>.

  • Se l'elenco è popolato tutto in una volta dai dati ordinati, SortedList<TKey, TValue> è più veloce di SortedDictionary<TKey, TValue>.

(SortedList mantiene in realtà un array ordinato, piuttosto che utilizzare un albero Esso utilizza ancora la ricerca binaria per trovare gli elementi..)

+0

Grazie v molto a tutti per i suggerimenti. Suppongo di essere troppo pigro per RTFM ... molto più facile da chiedere ai simpatici ragazzi di SO ...;) Ho votato entrambi per le risposte; Jon ottiene il credito di risposta per essere stato il primo a fare il grilletto. :) –

+2

Penso che la definizione SortedList debba essere corretta in quanto non credo che sia un albero di ricerca binario ...? – nchaud

+1

Ho guardato usando il reflector e ho scoperto che non utilizzava un albero di ricerca binario. –

12

Scopri i MSDN page for SortedList:

Da sezione Osservazioni:

La classe generica SortedList<(Of <(TKey, TValue>)>) è un albero di ricerca binario con recupero O(log n), dove n è il numero di elementi nel dizionario. In questo, è simile alla classe generica SortedDictionary<(Of <(TKey, TValue>)>). Le due classi hanno modelli di oggetti simili ed entrambi hanno il recupero da O(log n). Dove i due classi differiscono è in uso la memoria e la velocità di inserimento e rimozione:

  • SortedList<(Of <(TKey, TValue>)>) utilizza meno memoria SortedDictionary<(Of <(TKey, TValue>)>).
  • SortedDictionary<(Of <(TKey, TValue>)>) ha operazioni di inserimento e rimozione più rapide per dati non ordinati, O(log n) in confronto a O(n) per SortedList<(Of <(TKey, TValue>)>).

  • Se l'elenco viene popolato tutto in una volta da dati ordinati, SortedList<(Of <(TKey, TValue>)>) è più veloce di SortedDictionary<(Of <(TKey, TValue>)>).

+8

Il testo citato è errato (ed è stato aggiornato su MSDN): SortedList non è un "albero di ricerca binario", è un "array di coppie chiave/valore". –

20

ho incrinato Reflector aperto a dare un'occhiata a questo come sembra che ci sia un po 'di confusione su SortedList. In realtà non è un albero di ricerca binario, è una matrice ordinata (per chiave) di coppie chiave-valore. Esiste anche una variabile TKey[] keys ordinata in sincronia con le coppie chiave-valore e utilizzata per la ricerca binaria.

Ecco alcune fonti (con targeting .NET 4.5) per il backup delle mie attestazioni.

membri privati ​​

// Fields 
private const int _defaultCapacity = 4; 
private int _size; 
[NonSerialized] 
private object _syncRoot; 
private IComparer<TKey> comparer; 
private static TKey[] emptyKeys; 
private static TValue[] emptyValues; 
private KeyList<TKey, TValue> keyList; 
private TKey[] keys; 
private const int MaxArrayLength = 0x7fefffff; 
private ValueList<TKey, TValue> valueList; 
private TValue[] values; 
private int version; 

SortedList.ctor (IDictionary, IComparer)

public SortedList(IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer) : this((dictionary != null) ? dictionary.Count : 0, comparer) 
{ 
    if (dictionary == null) 
    { 
     ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary); 
    } 
    dictionary.Keys.CopyTo(this.keys, 0); 
    dictionary.Values.CopyTo(this.values, 0); 
    Array.Sort<TKey, TValue>(this.keys, this.values, comparer); 
    this._size = dictionary.Count; 
} 

SortedList.Add (TKey, TValue): void

public void Add(TKey key, TValue value) 
{ 
    if (key == null) 
    { 
     ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); 
    } 
    int num = Array.BinarySearch<TKey>(this.keys, 0, this._size, key, this.comparer); 
    if (num >= 0) 
    { 
     ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate); 
    } 
    this.Insert(~num, key, value); 
} 

SortedList.RemoveAt (int): void

public void RemoveAt(int index) 
{ 
    if ((index < 0) || (index >= this._size)) 
    { 
     ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index); 
    } 
    this._size--; 
    if (index < this._size) 
    { 
     Array.Copy(this.keys, index + 1, this.keys, index, this._size - index); 
     Array.Copy(this.values, index + 1, this.values, index, this._size - index); 
    } 
    this.keys[this._size] = default(TKey); 
    this.values[this._size] = default(TValue); 
    this.version++; 
} 
74

Qui è una vista tabellare se aiuta ...

Dal punto di vista delle prestazioni :

+------------------+---------+----------+--------+----------+----------+---------+ 
| Collection  | Indexed | Keyed | Value | Addition | Removal | Memory | 
|     | lookup | lookup | lookup |   |   |   | 
+------------------+---------+----------+--------+----------+----------+---------+ 
| SortedList  | O(1) | O(log n) | O(n) | O(n)* | O(n)  | Lesser | 
| SortedDictionary | n/a  | O(log n) | O(n) | O(log n) | O(log n) | Greater | 
+------------------+---------+----------+--------+----------+----------+---------+ 

* Insertion is O(1) for data that are already in sort order, so that each 
    element is added to the end of the list (assuming no resize is required). 

Dal punto di implementazione prospettiva:

+------------+---------------+----------+------------+------------+------------------+ 
| Underlying | Lookup  | Ordering | Contiguous | Data  | Exposes Key & | 
| structure | strategy  |   | storage | access  | Value collection | 
+------------+---------------+----------+------------+------------+------------------+ 
| 2 arrays | Binary search | Sorted | Yes  | Key, Index | Yes    | 
| BST  | Binary search | Sorted | No   | Key  | Yes    | 
+------------+---------------+----------+------------+------------+------------------+ 

A a circa parafrasi, se si richiede prestazioni raw SortedDictionary potrebbe essere una scelta migliore. Se si richiede un sovraccarico di memoria e un recupero indicizzati minori, SortedList si adatta meglio. See this question for more on when to use which.

Si può leggere di più here, here, here, here e here.

+0

Si noti che se si desidera ottenere prestazioni ottimali ** e ** utilizzo memoria relativamente basso ** e ** recupero indicizzato, considerare ['BDictionary ' in LoycCore] (http://loyc.net/doc/code/classLoyc_1_1Collections_1_1BDictionary_3_01K_00_01V_01_4.html) invece di 'SortedDictionary'. – Qwertie

+0

@Qwertie è disponibile un benchmark delle prestazioni? – nawfal

+1

Sì, guarda la parte inferiore di [questo articolo] (http://core.loyc.net/collections/alists-part3.html). Si scopre che 'BDictionary' di solito è più lento di' SortedDictionary' ad eccezione delle dimensioni molto grandi, ma è più veloce di 'SortedList' se ci sono oltre 700 elementi o giù di lì. L'uso della memoria dovrebbe essere solo leggermente superiore a 'SortedList' (molto più basso di' SortedDictionary'), a causa dell'uso di array nelle foglie dell'albero. – Qwertie

9

Questa è la rappresentazione visiva di come le prestazioni si confrontano tra loro.

0

accesso Index (citato qui) è la differenza pratica. Se è necessario accedere al successore o al predecessore, è necessario SortedList. SortedDictionary non può farlo, quindi sei abbastanza limitato da come puoi usare l'ordinamento (first/foreach).

2

Già si dice già sull'argomento, tuttavia per semplificare, ecco la mia opinione.

dizionario Ordinati dovrebbe essere usato quando- sono tenuti

  • Più inserti e le operazioni di eliminazione.
  • Dati non ordinati.
  • L'accesso chiave è sufficiente e non è richiesto l'accesso all'indice.
  • La memoria non è un collo di bottiglia.

Sull'altro lato, elenco ordinato deve essere utilizzato quando- sono richiesti

  • Altre ricerche e meno inserti e operazioni di eliminazione.
  • I dati sono già ordinati (se non tutti, la maggior parte).
  • È necessario l'accesso all'indice.
  • La memoria è un sovraccarico.

Spero che questo aiuti !!