私はBlockingCollectionクラスをいじってみましたが、なぜToArray()メソッドがO(n)操作であるのか疑問に思いました。Javaのバックグラウンドから来たArrayListのToArray()メソッドは、使用する内部配列(elementData)を返すだけなので、O(1)で実行されます。では、なぜ世界ですべてのアイテムを反復処理し、IEnumerable.ToArrayメソッドで新しい配列を作成するのに、それをオーバーライドしてコレクションが使用する内部配列を返すことができるのでしょうか。
3 に答える
Javaのバックグラウンドから来たArrayListのToArray()メソッドは、使用する内部配列(elementData)を返すだけなので、O(1)で実行されます。
いいえ、実際にはそうではありません。配列のコピーを作成します。のドキュメントArrayList.toArray
から:
このリストのすべての要素を適切な順序で(最初の要素から最後の要素まで)含む配列を返します。
返される配列は、このリストによって参照が維持されないという点で「安全」です。(つまり、このメソッドは新しい配列を割り当てる必要があります)。したがって、呼び出し元は返された配列を自由に変更できます。
つまり、基本的に、あなたの質問の前提はJavaの意味で欠陥があります。
さて、それを超えると、シーケンスが配列によって裏付けられるという保証がないため、一般Enumerable.ToArray
に(の拡張メソッドIEnumerable<T>
)はO(N)になります。に裏打ちされている場合、それは物事をより効率的にするために使用されますが、これは実装固有の詳細であり、それでもO(1)操作に変換されません。IList<T>
IList<T>.CopyTo
ArrayList.toArray
はO(1)ではなく、内部配列を返すだけではありません。API仕様を読みましたか?
返される配列は、このリストによって参照が維持されないという点で「安全」です。(つまり、このメソッドは新しい配列を割り当てる必要があります)。したがって、呼び出し元は返された配列を自由に変更できます。
まず、返す配列がありません。内部ストレージにBlockingCollection<T>
型のオブジェクトを使用します。使用されている具象型が配列によって裏付けられるという保証はありません。IProducerConsumerCollection<T>
たとえば、デフォルトのコンストラクターは、ConcurrentQueue<T>
データを配列のリンクリストに格納するを使用します。コレクションの完全なコンテンツを表す配列がどこかに隠れているという奇妙な場合でも、IProducerConsumerCollection<T>
インターフェイスを介して公開されることはありません。
第二に、最初に返される配列があったとしても(それはありません)、それは安全なことではありません。呼び出し元のコードが配列に変更を加えた場合、コレクションの内部状態が破損します。