В чем разница между SortedList и SortedDictionary?

261

Есть ли реальная практическая разница между а SortedList<TKey,TValue>и а SortedDictionary<TKey,TValue>? Есть ли какие-то обстоятельства, когда вы бы специально использовали один, а не другой?

Шауль Бер
источник
13
Я запутался. Почему SortedList имеет два параметра типа, SortedList<TKey,TValue>а не один SortedList<T>? Почему это не реализуется IList<T>?
полковник Паник
3
@ColonelPanic, потому что функционально SortedList - это карта, а не линейная коллекция. Не позволяйте имени обмануть вас. Точно так же как словарь, вы передаете ключ, вы получаете значение обратно. Пока словарь не упорядочен, SortedList упорядочен в естественном порядке.
nawfal

Ответы:

294

Да, их эксплуатационные характеристики существенно различаются. Вероятно, было бы лучше назвать их, SortedListи, SortedTreeпоскольку это отражает реализацию более тесно.

Посмотрите документы MSDN для каждого из них ( SortedList, SortedDictionary), чтобы узнать подробности производительности для различных операций в разных ситуациях. Вот хорошее резюме (из SortedDictionaryдокументов):

SortedDictionary<TKey, TValue>Общий класс представляет собой бинарное дерево поиска с O (журнал п) извлечения, где п число элементов в словаре. В этом он похож на SortedList<TKey, TValue>общий класс. Два класса имеют похожие объектные модели, и оба имеют O (log n) извлечения. Два класса различаются в использовании памяти и скорости вставки и удаления:

  • SortedList<TKey, TValue>использует меньше памяти, чем SortedDictionary<TKey, TValue>.

  • SortedDictionary<TKey, TValue>имеет более быстрые операции вставки и удаления для несортированных данных, O (log n), в отличие от O (n) для SortedList<TKey, TValue>.

  • Если список заполняется сразу из отсортированных данных, SortedList<TKey, TValue>это быстрее, чем SortedDictionary<TKey, TValue>.

( SortedListфактически поддерживает отсортированный массив, а не использует дерево. Он все еще использует бинарный поиск для поиска элементов.)

Джон Скит
источник
Большое спасибо всем за указатели. Я полагаю, что мне просто лень RTFM ... намного проще спросить приятных людей на SO ...;) Я проголосовал за то, чтобы вы оба ответили; Джон получает ответ за то, что был первым на спусковом крючке. :)
Shaul Behr
2
Я думаю, что определение SortedList должно быть исправлено, так как я не верю, что это двоичное дерево поиска ...?
nchaud
1
Я посмотрел с помощью отражателя и обнаружил, что он не использует двоичное дерево поиска.
Даниэль Иммс
Я думаю, что Sorteddictionary - это AVL-дерево или Red-Blacktree (все операции стоят O (logn). А SortedList - это бинарный поиск (в худшем случае это o (n) раз) l
Ghoster
105

Вот табличное представление, если это помогает ...

С точки зрения производительности :

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

С точки зрения реализации :

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

Чтобы примерно парафраз, если вам требуется сырец производительность SortedDictionaryможет быть лучшим выбором. Если вам требуется меньшая нагрузка на память и индексированный поиск, то это SortedListлучше. Смотрите этот вопрос для получения дополнительной информации о том, когда использовать который.

Вы можете прочитать больше здесь , здесь , здесь , здесь и здесь .

Навфал
источник
Обратите внимание, что если вы хотите хорошую производительность и относительно низкое использование памяти и индексированный поиск, используйте BDictionary<Key,Value>LoycCore вместо SortedDictionary.
Qwertie
1
Да, посмотрите на нижнюю часть этой статьи . Оказывается, BDictionaryэто обычно медленнее, чем SortedDictionaryза исключением очень больших размеров, но это быстрее, чем SortedListесли есть более 700 предметов или около того. Использование памяти должно быть только немного выше, чем SortedList(намного ниже, чем SortedDictionary), из-за использования массивов в листьях дерева.
Qwertie
22

Я взломал Reflector, чтобы взглянуть на это, так как кажется, что это немного путаница SortedList. На самом деле это не двоичное дерево поиска, это отсортированный (по ключу) массив пар ключ-значение . Существует также TKey[] keysпеременная, которая сортируется синхронно с парами ключ-значение и используется для двоичного поиска.

Вот некоторый источник (нацеленный на .NET 4.5) для резервного копирования моих утверждений.

Частные участники

// 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++;
}
Даниэль Иммс
источник
13

Проверьте страницу MSDN для SortedList :

Из раздела «Замечания»:

SortedList<(Of <(TKey, TValue>)>)Общий класс представляет собой бинарное дерево поиска с O(log n)поиском, где nесть число элементов в словаре. В этом он похож на SortedDictionary<(Of <(TKey, TValue>)>)общий класс. Два класса имеют похожие объектные модели, и оба имеют O(log n)поиск. Два класса различаются в использовании памяти и скорости вставки и удаления:

  • SortedList<(Of <(TKey, TValue>)>)использует меньше памяти, чем SortedDictionary<(Of <(TKey, TValue>)>).
  • SortedDictionary<(Of <(TKey, TValue>)>)имеет более быструю вставку и операции по удалению для неупорядоченных данных, O(log n)в отличие от O(n)для SortedList<(Of <(TKey, TValue>)>).

  • Если список заполняется сразу из отсортированных данных, SortedList<(Of <(TKey, TValue>)>)это быстрее, чем SortedDictionary<(Of <(TKey, TValue>)>).

Stephan
источник
9
Текст в кавычках неверен (и был обновлен в MSDN): SortedList - это не «двоичное дерево поиска», это «массив пар ключ / значение».
Eldritch Conundrum
12

Это визуальное представление о том, как спектакли сравниваются друг с другом.

лев
источник
Откуда вы взяли эту информацию? Из этой схемы мы видим, что Dictinary лучше в любом случае, поэтому нет никаких оснований для существования других.
Алекс Костин
9

Уже достаточно сказано по этой теме, однако, чтобы было проще, вот мое мнение.

Сортированный словарь должен использоваться, когда

  • Требуется больше операций вставки и удаления.
  • Данные в неупорядоченном виде.
  • Доступ к ключу достаточен, и индексный доступ не требуется.
  • Память не является узким местом.

С другой стороны, отсортированный список следует использовать, когда

  • Требуется больше поисков и меньше операций вставки и удаления.
  • Данные уже отсортированы (если не все, большинство).
  • Индекс доступа требуется.
  • Память - это накладные расходы.

Надеюсь это поможет!!

Пракаш Трипати
источник
1

Индексный доступ (упомянутый здесь) - это практическая разница. Если вам нужен доступ к преемнику или предшественнику, вам нужен SortedList. SortedDictionary не может этого сделать, поэтому вы довольно ограничены тем, как вы можете использовать сортировку (first / foreach).

парень
источник