最近、Scalaの学習を始めて、::
(cons)関数。リストの先頭に追加します。
本「Programming in Scala」では、リストへの追加はパフォーマンスo(n)であるのに対し、先頭に追加するとo(1 )
その声明について何かが私を間違っているように思わせます。
パフォーマンスは実装に依存していませんか?順方向リンクと逆方向リンクの両方を使用してリストを単純に実装し、最初と最後の要素をコンテナーに格納することはできませんか?
2つ目の質問は、リストが1、2、3で、リストの最後に4を追加したい場合にどうすればよいでしょうか。
重要なのはx :: somelist
はsomelist
を変更しませんが、代わりにxとそれに続くsomelist
のすべての要素を含む新しいリストを作成します。これは、O(1)時間で実行できます。これは、新しく作成された単一リンクリストのsomelist
の後続としてx
を設定するだけでよいためです。
代わりに二重リンクリストを使用した場合、x
もsomelist
を変更するsomelist
のヘッドの先行として設定する必要があります。だから私たちができるようにしたいなら::
in O(1)元のリストを変更せずに、単一リンクリストのみを使用できます。
2番目の質問について::::
は、単一要素のリストをリストの最後に連結します。これはO(n)操作です。
List(1,2,3) ::: List(4)
他の回答は、この現象をうまく説明しています。サブルーチンのリストに多くのアイテムを追加する場合、または要素を追加してリストを作成する場合、機能的な慣用法は、リストを逆の順序で作成し、リストの前、最後に逆にします。これにより、O(n²)の代わりにO(n)パフォーマンスが得られます。
質問が更新されたばかりなので、ここで物事が変更されたことに注目する価値があります。
今日のScalaでは、単にxs :+ x
は、順次コレクションの最後にアイテムを追加します。 (もあります x +: xs
を先頭に追加します。 Scalaの2.8以降のコレクション操作の多くのニーモニックは、 colの隣に行く col選挙。)
これは、List
またはSeq
のデフォルトのリンクされた実装ではO(n)になりますが、Vector
またはIndexedSeq
、これは実質的に一定の時間になります。 ScalaのVector
は、最近のほとんど役に立たないJavaのVector
とは異なり、おそらくScalaの最も便利なリストのようなコレクションです。
Scala 2.8以上で作業している場合、 コレクションの紹介 は絶対に読む必要があります。
プリペンディングは2つの操作のみを必要とするため、より高速です。
ヘッドへのポインタしかないため、リストの最後まで走査する必要があるため、追加にはさらに操作が必要です。
私はScalaでプログラムしたことがありませんが、 List Buffer を試すことができます
ほとんどの関数型言語は、便利な不変のコレクション型であるため、シングルリンクリストのデータ構造を際立たせています。関数型言語で「リスト」と言うと、通常、それが意味します(単一リンクリスト、通常は不変)。そのような型の場合、appendはO(n)ですが、consはO(1)です。