Есть ли реальная практическая разница между SortedList<TKey,TValue>
и SortedDictionary<TKey,TValue>
? Существуют ли какие-либо обстоятельства, при которых вы конкретно использовали бы один, а не другой?
Какая разница между SortedList и SortedDictionary?
Ответ 1
Да - их характеристики производительности значительно различаются. Вероятно, было бы лучше назвать их SortedList
и SortedTree
, поскольку это более точно отражает реализацию.
Посмотрите документы MSDN для каждого из них (SortedList
, SortedDictionary
) для получения подробной информации о производительности для разных операций в разных ситуациях. Здесь хорошее резюме (из SortedDictionary
docs):
SortedDictionary<TKey, TValue>
общий class является двоичным деревом поиска с O (log n), где n - количество элементов в словаре. В этом он аналогичен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
фактически поддерживает отсортированный массив, а не использует дерево. Он по-прежнему использует двоичный поиск для поиска элементов.)
Ответ 2
Вот табличное представление, если оно помогает...
С точки зрения производительности:
+------------------+---------+----------+--------+----------+----------+---------+
| 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
подходит лучше. См. этот вопрос для получения дополнительных сведений о том, когда использовать.
Вы можете прочитать здесь здесь, здесь, здесь, здесь и здесь.
Ответ 3
Я взломал 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++;
}
Ответ 4
Просмотрите страницу 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>)>)
.
Ответ 5
Это визуальное представление того, как характеристики сравниваются друг с другом.
Ответ 6
Достаточно сказано уже на эту тему, однако, чтобы это было просто, вот мое занятие.
Сортированный словарь должен использоваться, когда -
- Требуются дополнительные операции вставки и удаление.
- Данные не упорядочены.
- Доступ к ключам достаточно, и доступ к индексу не требуется.
- Память не является узким местом.
С другой стороны, Сортированный список следует использовать, когда -
- Требуется больше запросов и меньше операций вставки и удаления.
- Данные уже отсортированы (если не все, большинство).
- Требуется доступ к индексу.
- Память - это накладные расходы.
Надеюсь, это поможет!
Ответ 7
Доступ к индексу (упомянутый здесь) является практическим различием. Если вам нужно получить доступ к преемнику или предшественнику, вам потребуется SortedList. SortedDictionary не может этого сделать, поэтому вы достаточно ограничены тем, как вы можете использовать сортировку (first/foreach).