2010-11-27 9 views
13
prefixes ls = zipWith take [1 .. length ls] (repeat ls) 

これより優れた方法はありますか?直感的には、reverseまたはappendをn回適用する必要があるため、純粋に関数型言語でO(n²)以下のアルゴリズムを得ることはできないようです。しかし、私はこれをどのように証明するのか分かりません。リストのすべてのプレフィックスを生成する最も効率的な純粋に機能的なアルゴリズムは何ですか?

答えて

19

あなたは正しいと思います。すべての尾が異なるため、リストの背骨を共有することはできません。したがって、プレフィックスのリストが完全に評価された場合、Θ(n )のスペースが必要です。生成には、Ω(n )時間かかる場合があります。

あなたが書いた関数の(よりレイジーなバージョン)は、Data.Listinitsとして利用可能であることに注意してください。

あなたはきちんとした最適化ができます。この方程式は、

map (foldl f z) . inits = scanl f z 

と、scanlが線形時間で実行されます。ですから、各接頭辞にしたいことを左折としてフレーズできれば、接頭辞のリストを作成するという二次的な複雑さを避けることができます。

+2

+1 scanlの素晴らしいアイディア –

3

これは表現に依存しませんか?リストを連続したストレージと開始インデックスと終了インデックス(バイト列に似ています)として表現すると、ストレージを共有でき、インデックスのリストを構築するために一度トラバースするだけで済みます。アルゴリズムは変更されず、表現だけが変更されます。この特定のユースケースでは、snocリスト(バイナリリストではなく、リストの始めから終わりに入れ子になっています)を使ってサブリストを共有することもできます。

+0

彼の質問は普通のハッスルリスト '[]'を対象としていることは比較的明確だと思います。 -1 – fuz

+2

これは、例の構文を見ているのか、それとも質問のとおりであるのかによって異なります。受け入れられた答えを考えると、バイナリリストへの制限が意図されている可能性があります。しかし、これは純粋に機能的なアルゴリズムの特性ではなく、この特定のリスト表現のようなハスケルのアルゴリズムさえも含みません。 – claus

+0

はい、バイナリリストへの制限が意図されていました。私はそれをより明確にすることができた。 –

関連する問題