web-dev-qa-db-fra.com

Quelle est la différence entre SortedList et SortedDictionary?

Existe-t-il une réelle différence pratique entre un SortedList<TKey,TValue> et un SortedDictionary<TKey,TValue> ? Y a-t-il des circonstances dans lesquelles vous utiliseriez spécifiquement l'un et pas l'autre?

247
Shaul Behr

Oui, leurs caractéristiques de performance diffèrent considérablement. Il serait probablement préférable de les appeler SortedList et SortedTree, car cela reflète plus précisément la mise en œuvre.

Examinez les documents MSDN pour chacune d’elles ( SortedList , SortedDictionary ) pour obtenir des détails sur les performances de différentes opérations dans différentes situations. Voici un bon résumé (de la SortedDictionarydocs):

Le SortedDictionary<TKey, TValue> La classe générique est un arbre de recherche binaire avec une extraction O (log n), où n est le nombre d'éléments du dictionnaire. En cela, il est similaire au SortedList<TKey, TValue> classe générique. Les deux classes ont des modèles d'objet similaires et les deux ont une extraction O (log n). La différence entre les deux classes est l'utilisation de la mémoire et la vitesse d'insertion et de suppression:

  • SortedList<TKey, TValue> utilise moins de mémoire que SortedDictionary<TKey, TValue>.

  • SortedDictionary<TKey, TValue> a des opérations d’insertion et de suppression plus rapides pour les données non triées, O (log n) par opposition à O(n) pour SortedList<TKey, TValue>.

  • Si la liste est remplie en une fois à partir de données triées, SortedList<TKey, TValue> est plus rapide que SortedDictionary<TKey, TValue>.

(SortedList maintient en fait un tableau trié, plutôt que d'utiliser un arbre. Il utilise toujours la recherche binaire pour trouver des éléments.)

283
Jon Skeet

Voici une vue tabulaire si cela peut aider ...

Dans une perspective performance :

+------------------+---------+----------+--------+----------+----------+---------+
| 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).

Dans une perspective d'implémentation :

+------------+---------------+----------+------------+------------+------------------+
| 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              |
+------------+---------------+----------+------------+------------+------------------+

Pour approximativement paraphraser, si vous avez besoin de performances brutes, SortedDictionary pourrait être un meilleur choix. Si vous avez besoin d'une surcharge de mémoire et d'une récupération indexée, SortedList convient mieux. Voir cette question pour en savoir plus sur quand utiliser lequel.

Vous pouvez en lire plus ici , ici , ici , ici et ici .

97
nawfal

J'ai craqué d'ouvrir Reflector pour jeter un coup d'œil à ceci car il semble y avoir un peu de confusion à propos de SortedList. Ce n'est en fait pas un arbre de recherche binaire, c'est un tableau trié (par clé) de paires clé-valeur. Il y a aussi TKey[] keys variable qui est triée de manière synchrone avec les paires clé-valeur et utilisée pour la recherche binaire.

Voici quelques sources (ciblant .NET 4.5) pour sauvegarder mes revendications.

membres privés

// 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++;
}
21
Daniel Imms

Découvrez la page MSDN pour SortedList :

De la section Remarques:

La classe générique SortedList<(Of <(TKey, TValue>)>) est un arbre de recherche binaire avec la récupération O(log n), où n est le nombre d'éléments dans le dictionnaire. En cela, il est similaire à la classe générique SortedDictionary<(Of <(TKey, TValue>)>). Les deux classes ont des modèles d'objet similaires et les deux ont la récupération O(log n). La différence entre les deux classes est l'utilisation de la mémoire et la vitesse d'insertion et de suppression:

  • SortedList<(Of <(TKey, TValue>)>) utilise moins de mémoire que SortedDictionary<(Of <(TKey, TValue>)>).
  • SortedDictionary<(Of <(TKey, TValue>)>) a des opérations d'insertion et de suppression plus rapides pour les données non triées, O(log n) par opposition à O(n) pour SortedList<(Of <(TKey, TValue>)>).

  • Si la liste est remplie en une fois à partir de données triées, SortedList<(Of <(TKey, TValue>)>) est plus rapide que SortedDictionary<(Of <(TKey, TValue>)>).

13
Stephan

Ceci est une représentation visuelle de la façon dont les performances se comparent les unes aux autres.

11
Lev

On en dit déjà assez sur le sujet, mais pour rester simple, voici mon point de vue.

Dictionnaire trié devrait être utilisé quand-

  • Davantage d'insertions et d'opérations de suppression sont requises.
  • Données non commandées.
  • L'accès à la clé est suffisant et l'accès à l'index n'est pas requis.
  • La mémoire n'est pas un goulot d'étranglement.

De l'autre côté, Liste triée devrait être utilisé lorsque-

  • Plus de recherches et moins d'insertions et d'opérations de suppression sont nécessaires.
  • Les données sont déjà triées (sinon toutes, la plupart).
  • L'accès à l'index est requis.
  • La mémoire est une surcharge.

J'espère que cela t'aides!!

8
Prakash Tripathi

L'accès à l'index (mentionné ici) est la différence pratique. Si vous devez accéder au successeur ou au prédécesseur, vous avez besoin de SortedList. SortedDictionary ne peut pas faire cela, donc vous êtes assez limité avec la façon dont vous pouvez utiliser le tri (first/foreach).

0
Guy