.NETデータ構造:ArrayList、List、HashTable、Dictionary、SortedList、SortedDictionary —速度、メモリ、およびそれぞれをいつ使用するか?


213

.NETには、多くの複雑なデータ構造があります。残念ながら、それらのいくつかは非常によく似ており、いつ使用するか、いつ使用するかは常にわかりません。私のC#とVisual Basicの本のほとんどは、ある程度それらについて語っていますが、実際には詳細には触れていません。

Array、ArrayList、List、Hashtable、Dictionary、SortedList、およびSortedDictionaryの違いは何ですか?

どれが列挙可能ですか(IList-'foreach'ループを実行できます)?キーと値のペア(IDict)を使用するのはどれですか。

メモリフットプリントはどうですか?挿入速度は?検索速度は?

言及する価値のある他のデータ構造はありますか?

私はまだメモリ使用量と速度(Big-O表記)の詳細を探しています。


12
この質問はバラバラにすべきです。あなたは20の異なることを尋ねていますが、その半分は単純なGoogle検索で答えることができます。より具体的にしてください。あなたの質問がとても散らばっているとき、助けるのは難しいです。

33
私はそれを分割することを考えましたが、誰かがこれらすべての答えを1つの場所に統合できる可能性が高いことに気づきました。実際、誰かがすべてをプロファイリングするテーブルを思い付くことができれば、それはこのサイトの素晴らしいリソースになるかもしれません。
プレッツェル

9
この質問をwikiに変えることはできますか?
BozoJoe、2011年

1
このMSDNの記事では、ツリー、グラフ、セットなどのこれらの質問の多くについて説明しています。データ構造の広範な調査
Ryan Fisher

1
ライアン、そのリンクの記事は14歳です(投稿時は12)。サイドノート私は先週自分自身でそれらを読んでいます。しかし、それらにはまた、より新しいテクノロジーが含まれておらず、必死にアップデートが必要です。そして、より多くのパフォーマンス指標と例。
htm11h

回答:


156

私の頭の上から:

  • Array*-昔ながらのメモリ配列を表しtype[]ます。通常の配列のエイリアスのようなものです。列挙できます。自動的に成長することはできません。非常に高速な挿入と検索の速度を想定しています。

  • ArrayList-自動的に成長する配列。オーバーヘッドを追加します。列挙できます。通常のアレイよりも低速ですが、それでもかなり高速です。これらは.NETでよく使用されます

  • List-私のお気に入りの1つ-ジェネリックで使用できるため、強く型付けされた配列を使用できますList<string>。それ以外は、ArrayList

  • Hashtable-プレーンな古いハッシュテーブル。O(1)からO(n)の最悪の場合。値とキーのプロパティを列挙し、キーと値のペアを実行できます

  • Dictionary -上記と同じように、ジェネリックを介してのみ強く型付けされます。 Dictionary<string, string>

  • SortedList-ソートされた汎用リスト。どこに物を置くかを理解する必要があるため、挿入が遅くなります。列挙できます。再検索する必要がないため、おそらく取得時に同じですが、削除は通常の古いリストよりも遅くなります。

私が使用する傾向があるListDictionary、すべての時間を-あなたは彼らが強く、ジェネリックで型指定された使用を開始したら、その本当にハードでは標準的な非ジェネリックのものに戻ります。

他にもたくさんのデータ構造があります- KeyValuePairあなたがいくつかの興味深いことをするために使うことができるものがありSortedDictionaryます、そして、それは同様に役立つことができるものがあります。


3
ハッシュテーブルはO(1)で、最悪のケース(衝突あり)はO(n)になる可能性があります
Justin Bozonier 08年

7
ここに追加する必要がある他の多くのデータ構造があります。LinkedList、Skip List、Stack、Queue、Heap、Trees、Graphsなど。これらも非常に重要なデータ構造です。
DarthVader 2011

2
.Net 4.0に追加されたConcurrentDictionaryは、スレッドセーフティを備えた一般的な辞書を提供します
Harindaka

2
また、BlockingCollection <T>はスレッドセーフのプロデューサー/コンシューマー実装を提供します
Harindaka

7
ArrayList仮想メソッドを使用しますが、使用List<T>しません。標準コレクションおよびカスタムコレクションの基本クラスとしてArrayList主に置き換えられました。主にに置き換えられました。私は避けることをお勧めし、新しいコードのために。List<T>Collection<T>HashtableDictionary<TKey, TValue>ArrayListHashtable
Sam Harwell 2013年

29

可能であれば、ジェネリックを使用してください。 これも:

  • ArrayListの代わりにリスト
  • HashTableの代わりに辞書

24

まず、.NETのすべてのコレクションはIEnumerableを実装します。

第二に、ジェネリックはフレームワークのバージョン2.0で追加されたため、多くのコレクションは重複しています。

したがって、一般的なコレクションは機能を追加する可能性がありますが、ほとんどの場合:

  • Listは、ArrayListの一般的な実装です。
  • 辞書はHashtableの一般的な実装です

配列は固定サイズのコレクションであり、特定のインデックスに格納されている値を変更できます。

SortedDictionaryは、キーに基づいてソートされるIDictionaryです。SortedListは、必要なIComparerに基づいてソートされるIDictionaryです。

したがって、IDictionary実装(KeyValuePairをサポートするもの)は次のとおりです。* Hashtable * Dictionary * SortedList * SortedDictionary

.NET 3.5で追加された別のコレクションは、ハッシュセットです。集合演算をサポートするコレクションです。

また、LinkedListは標準のリンクリスト実装です(リストは、より高速な検索のための配列リストです)。


20

ここでは、いくつかの一般的なヒントを示します。

  • foreachを実装する型で使用できますIEnumerableIList基本的に、IEnumberablewith CountおよびItem(ゼロベースのインデックスを使用してアイテムにアクセスする)プロパティです。IDictionary一方、任意のハッシュ可能なインデックスによってアイテムにアクセスできることを意味します。

  • ArrayArrayListおよびListすべての実装IListDictionarySortedDictionary、およびHashtable実装しますIDictionary

  • .NET 2.0以降を使用している場合は、前述のタイプの一般的な対応物を使用することをお勧めします。

  • これらのタイプのさまざまな操作の時間とスペースの複雑さについては、それらのドキュメントを参照してください。

  • .NETデータ構造はSystem.Collections名前空間にあります。追加のデータ構造を提供するPowerCollectionsなどのタイプライブラリがあります。

  • データ構造を完全に理解するには、CLRSなどのリソースを参照してください。


1
msdnから、sortedListはIDictionnaryを実装しているようです-IListではありません
Haim Bendanan

修繕。コメントありがとうございます。SortedListはキー/値のリストを保持しているようで、基本的には辞書のデータを表します。私が最初に答えを書いたとき、このクラスがどのように機能したか覚えていない...
2016

9

.NETデータ構造:

ArrayListとListが実際に異なる理由についての詳細

配列

あるユーザーが言うように、配列は「古い学校」のコレクションです(はい、配列はの一部ではありませんが、コレクションと見なされますSystem.Collections)。しかし、他のコレクション、つまりタイトルにリストしたもの(ここでは、ArrayListおよびList(Of T))と比較して、配列について「古い」とは何ですか?配列を見て、基本から始めましょう。

まず、Microsoft .NETの配列は、「いくつかの[論理的に関連する]アイテムを単一のコレクションとして扱うことができるメカニズム」です(リンクされた記事を参照)。どういう意味ですか?配列は、個々のメンバー(要素)を順番に、開始アドレスとともにメモリに順番に格納します。配列を使用することで、そのアドレスから始まる順次格納された要素に簡単にアクセスできます。

それ以上に、101の一般的な概念のプログラミングに反して、配列は実際には非常に複雑になる可能性があります。

配列は、1次元、多次元、またはjaddedにすることができます(ジャグ配列は読む価値があります)。配列自体は、動的ではありません:初期化されたら、の配列のnサイズの埋蔵保持するのに十分なスペースn個のオブジェクトの数。配列内の要素数は増減できません。Dim _array As Int32() = New Int32(100)配列が100個のInt32プリミティブ型オブジェクトを含むために、メモリブロックに十分なスペースを予約します(この場合、配列は0を含むように初期化されます)。このブロックのアドレスがに返され_arrayます。

記事によると、共通言語仕様(CLS)では、すべての配列がゼロベースである必要があります。.NETの配列は、ゼロベースでない配列をサポートしています。ただし、これはあまり一般的ではありません。ゼロベースの配列の「共通性」の結果として、マイクロソフトはそのパフォーマンスの最適化に多くの時間を費やしきまし。したがって、SZにはそれらを操作するための特定の中間言語命令があるため、1次元のゼロベースの(SZ)配列は「特別」であり、(多次元などではなく)本当に配列の最良の実装です。

配列は常に参照によって(メモリアドレスとして)渡されます。これは配列パズルの重要な部分です。境界チェックは実行されますが(エラーがスローされます)、配列の境界チェックを無効にすることもできます。

繰り返しになりますが、配列の最大の障害は、配列のサイズを変更できないことです。それらには「固定」容量があります。ArrayListとList(Of T)の歴史を紹介します。

ArrayList-一般的でないリスト

ArrayList(およびList(Of T)-いくつかの重要な違いがありますが、ここで、後で説明します)は、(広義の)コレクションへの次の追加としておそらく最もよく考えられています。ArrayListはIList( 'ICollection'の子孫)インターフェイスを継承します。ArrayListは、それ自身であり、かさばるより必要- オーバーヘッド -リストより。

IList実装は、ArrayListを固定サイズのリスト(配列のような)として扱うことができます。ただし、ArrayListsによって追加された追加の機能を超えて、この場合のArrayLists(Arraysより)は著しく遅いため、固定サイズのArrayListsを使用する利点はありません。

私が読んだところ、ArrayListsをギザギザにすることはできません。「要素としての多次元配列の使用はサポートされていません」。ここでも、ArrayListsの棺の中にある別の釘。ArrayListも「型付け」されていません。つまり、すべての下で、ArrayListはオブジェクトの動的な配列ですObject[]。これには、ArrayListを実装するときに多くのボックス化(暗黙的)とボックス化解除(明示的)が必要になり、オーバーヘッドが増加します。

根拠のない考え:私は、ArrayListsが配列からリスト型のコレクションに移動しようとする試みの一種の粗野な概念の子であることを教授の1人から読んだり聞いたりしたことを覚えていると思います。コレクションに関してさらなる開発が行われたため、これらはもはや最良のオプションではありません

List(Of T):ArrayListがどのようになったか

メモリ使用量の違いは、List(Of Int32)が同じプリミティブ型を含むArrayListよりも56%少ないメモリを消費するほど十分に重要です(上記の紳士のリンクされたデモでは、8 MB対19 MB:ここでもリンクされています)。これは、64ビットマシンによって複合された結果です。この違いは、実際には2つのことを示しています。1つ目は、(1)ボックス化されたInt32タイプの「オブジェクト」(ArrayList)は、純粋なInt32プリミティブタイプ(List)よりもはるかに大きいことです。2番目(2)、64ビットマシンの内部動作の結果として、差は指数関数的です。

それで、違いは何ですか?そしてList(Of T)は何ですか?MSDNList(Of T)、「...インデックスでアクセスできるオブジェクトの強く型付けされたリスト」と定義しています。ここで重要なのは、「強く型付けされた」ビットです。List(Of T)は型を「認識」し、オブジェクトをその型として格納します。したがって、Int32は型Int32ではなくとして格納されObjectます。これにより、ボックス化とボックス化解除によって発生する問題が解消されます。

MSDNでは、この違いはプリミティブ型を格納するときにのみ影響し、参照型を格納しないと規定しています。また、違いは実際には500を超える要素という大きなスケールで発生します。さらに興味深いのは、MSDNのドキュメントに、「ArrayListクラスを使用する代わりに、List(Of T)クラスの型固有の実装を使用するほうが有利だ」と書かれていることです。

基本的に、List(Of T)はArrayListですが、より優れています。これは、ArrayListの「一般的な同等物」です。ArrayListと同様に、ソートされるまでは、ソートされることが保証されていません(図に移動)。List(Of T)にもいくつかの機能が追加されています。



3

彼らはインテリセンスでかなりよく綴られています。System.Collectionsと入力するだけです。またはSystem.Collections.Generics(推奨)を選択すると、使用可能なもののリストと簡単な説明が表示されます。


3

ハッシュテーブル/辞書はO(1)パフォーマンスです。つまり、パフォーマンスはサイズの関数ではありません。知っておくことが重要です。

編集:実際には、Hashtable / Dictionary <>ルックアップの平均時間の複雑さはO(1)です。


5
「パフォーマンス」というものはありません。複雑さは操作に依存します。たとえば、n個の要素をDictionary <>に挿入した場合、再ハッシュによりO(1)にはなりません。
Ilya Ryzhenkov 2008

2
参考までに、リハッシュを行っても、DictionaryはまだO(1)です。辞書が拡張される直前のシナリオを考えてみましょう。要素の半分(最後の拡張以降に追加されたもの)は、一度ハッシュされます。残りの半分は2回ハッシュされます。残りの半分、3回など。各要素に対して実行されるハッシュ操作の平均数は1 + 1/2 + 1/4 + 1/8 ... = 2になります。展開直後の状況は基本的に同じですが、すべての要素が1回余分にハッシュされているため(平均ハッシュカウントは3)。他のすべてのシナリオはそれらの間にあります。
スーパーキャット2011年

3

ジェネリックコレクションは、特に多くのアイテムを繰り返し処理するときに、ジェネリックコレクションよりもパフォーマンスが高くなります。これは、ボックス化とボックス化解除が行われないためです。


2

高頻度系統的取引エンジニアリングのためのHashtable vs Dictionaryに関する重要な注意:スレッドセーフティの問題

Hashtableは、複数のスレッドで使用するためにスレッドセーフです。辞書のパブリック静的メンバーはスレッドセーフですが、インスタンスメンバーはスレッドセーフであるとは限りません。

したがって、Hashtableはこの点で「標準」の選択のままです。


これは部分的に本当です。のHashtable同時に一つだけの作家と複数のリーダーで使用しても安全です。一方、Dictionary同時に変更されない限り、複数のリーダーでを使用しても安全です。
ブライアンメナード2011

間違いなく。ただし、トレーディングスペースでは、ライブマーケットデータから同時に読み取り、追加されたエントリを含む分析を実行しています。それはまた、何人のトレーダーがシステムを利用しているかにも依存します-それがあなただけであれば、明らかに問題ではありません。
ロブ

1
.NET 4.0はConcurrentDictionary <TKey、TValue>を提供します
Rob

1

ジェネリックコレクションと非ジェネリックコレクションの間には、微妙な違いがあります。それらは単に異なる基礎となるデータ構造を使用します。たとえば、Hashtableは、1人のライターが多数のリーダーを同期せずに保証します。辞書にはありません。


1

最も人気のあるC#データ構造とコレクション

  • アレイ
  • 配列リスト
  • リスト
  • LinkedList
  • 辞書
  • ハッシュセット
  • スタック
  • キュー
  • SortedList

C#.NETはさまざまなデータ構造があります。たとえば、最も一般的なものの1つは配列です。ただし、C#にはさらに多くの基本的なデータ構造が付属しています。使用する正しいデータ構造を選択することは、適切に構造化された効率的なプログラムを作成することの一部です。

この記事では、C#.NET 3.5で導入された新しいデータ構造を含む、組み込みのC#データ構造について説明します。これらのデータ構造の多くは他のプログラミング言語に適用されることに注意してください。

アレイ

おそらく最も単純で最も一般的なデータ構造は配列です。C#配列は、基本的にオブジェクトのリストです。その定義的な特徴は、すべてのオブジェクトが同じタイプであり(ほとんどの場合)、特定の数のオブジェクトがあることです。配列の性質により、リスト内の要素の位置(別名はインデックス)に基づいて、要素に非常に高速にアクセスできます。C#配列は次のように定義されています。

[object type][] myArray = new [object type][number of elements]

いくつかの例:

 int[] myIntArray = new int[5];
 int[] myIntArray2 = { 0, 1, 2, 3, 4 };

上記の例からわかるように、配列は、要素なしで、または既存の値のセットから初期化できます。配列への値の挿入は、それらが収まる限り簡単です。配列のサイズより多くの要素がある場合、操作はコストがかかります。その時点で、配列を拡張する必要があります。既存のすべての要素を新しい大きな配列にコピーする必要があるため、これには時間がかかります。

配列リスト

C#データ構造体ArrayListは動的配列です。つまり、ArrayListは任意の量のオブジェクトと任意のタイプを持つことができます。このデータ構造は、新しい要素を配列に追加するプロセスを簡略化するために設計されました。内部的には、ArrayListはスペースが不足するたびにサイズが2倍になる配列です。内部配列のサイズを2倍にすることは、長期的には要素コピーの量を減らす非常に効果的な方法です。ここではその証拠には触れません。データ構造は非常に簡単に使用できます。

    ArrayList myArrayList = new ArrayList();
    myArrayList.Add(56);
    myArrayList.Add("String");
    myArrayList.Add(new Form());

ArrayListデータ構造の欠点は、取得した値を元の型にキャストし直す必要があることです。

int arrayListValue = (int)myArrayList[0]

ここで見つけることができるソースと詳細情報


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.