web-dev-qa-db-ja.com

SortedListとSortedDictionaryの違いは何ですか?

SortedList<TKey,TValue>SortedDictionary<TKey,TValue> の間に実際の実際的な違いはありますか?どちらか一方を使用し、他方を使用しない状況はありますか?

247
Shaul Behr

はい-それらのパフォーマンス特性は大きく異なります。それらをSortedListおよびSortedTreeと呼ぶ方が、実装をより密接に反映するため、おそらくより良いでしょう。

それぞれの状況( SortedListSortedDictionary )については、MSDNのドキュメントを参照してください。ここに素敵な要約があります(SortedDictionaryドキュメントから):

SortedDictionary<TKey, TValue>ジェネリッククラスは、O(log n)を取得するバイナリ検索ツリーです。ここで、nはディクショナリ内の要素の数です。この点では、SortedList<TKey, TValue>ジェネリッククラスに似ています。 2つのクラスには類似したオブジェクトモデルがあり、両方ともO(log n)取得があります。 2つのクラスの違いは、メモリの使用と挿入および削除の速度です。

  • SortedList<TKey, TValue>は、SortedDictionary<TKey, TValue>よりも少ないメモリを使用します。

  • SortedDictionary<TKey, TValue>は、SortedList<TKey, TValue>のO(n)とは対照的に、ソートされていないデータ、O(log n)の挿入および削除操作が高速です。

  • ソートされたデータからリストが一度に作成される場合、SortedList<TKey, TValue>SortedDictionary<TKey, TValue>よりも高速です。

SortedListは、ツリーを使用するのではなく、実際にソートされた配列を保持します。それでも、要素を見つけるためにバイナリ検索を使用します。)

283
Jon Skeet

これが役立つ場合は、表形式のビューです...

パフォーマンスの観点から:

+------------------+---------+----------+--------+----------+----------+---------+
| 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の方が適しています。 whichをいつ使用するかの詳細については、この質問を参照してください。

もっと読むことができます herehereherehere and here .

97
nawfal

SortedListについて少し混乱しているように見えるので、Reflectorを開いてこれを確認しました。実際には、バイナリ検索ツリーではありませんキーと値のペアのソートされた(キーによる)配列です。キーと値のペアと同期してソートされ、バイナリ検索に使用される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++;
}
21
Daniel Imms

SortedListのMSDNページ をご覧ください。

備考セクションから:

SortedList<(Of <(TKey, TValue>)>)ジェネリッククラスは、O(log n)を取得するバイナリ検索ツリーです。nは、ディクショナリ内の要素の数です。この点では、SortedDictionary<(Of <(TKey, TValue>)>)ジェネリッククラスに似ています。 2つのクラスには類似したオブジェクトモデルがあり、両方ともO(log n)を取得します。 2つのクラスの違いは、メモリの使用と挿入および削除の速度です。

  • 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>)>)よりも高速です。

13
Stephan

これは、パフォーマンスを相互に比較する方法を視覚的に表したものです。

11
Lev

このトピックについては既に十分に述べられていますが、簡単にするために、ここに私の見解を示します。

ソートされた辞書は次の場合に使用する必要があります-

  • 追加の挿入および削除操作が必要です。
  • データは順不同です。
  • キーアクセスで十分であり、インデックスアクセスは必要ありません。
  • メモリはボトルネックではありません。

反対側では、Sorted Listは次の場合に使用する必要があります-

  • より多くの検索と、より少ない挿入および削除操作が必要です。
  • データはすでにソートされています(すべてではない場合、ほとんど)。
  • インデックスアクセスが必要です。
  • メモリはオーバーヘッドです。

お役に立てれば!!

8

インデックスアクセス(ここで説明)は実際的な違いです。後続または先行にアクセスする必要がある場合は、SortedListが必要です。 SortedDictionaryはそれを行うことができないため、並べ替えの使用方法(first/foreach)にはかなり制限があります。

0
Guy