文書ではData.Sequence.reverse
はO(n)です。有限シーケンス型をフラグを設定することによって "反転"できないか? (事実上、から「カウントを開始」するために、エンドいる。)なぜData.Sequence.reverse O(n)ですか?
答えて
フラグが1つだけの場合、問題が発生します。私はそれを計算することができる方法
xs <> reverse xs
たいと?ただ1つのフラグで、追加する前に高価な逆を実行する必要があります。実際にこれを行うには右、より多くの旗が必要です。 すべて木の周り。ツリー内のすべてのノードは、反転情報を運ぶ必要があります。これは間違いなく可能ですが、いくらか高価です。さらに悪いことに、すべての操作のすべてのステップで、反転フラグを適切に管理する必要があります。これは、誰でもコードを記述して維持する必要があります。このアイデアはどこかの紙の中で作られています(私はどちらが覚えていないのですか)が、実際には楽しいことではありません。
本質的に反転に依存するアルゴリズムを使用している場合は、多くのフラグを持つカスタムシーケンスタイプを使用し、必要な操作だけを含める必要があります(タイプをData.Sequence
に設定している場合は、各サイズフィールドから1ビット)。しかし、私はそのようなアルゴリズムはあまり一般的ではないと思う。
'><'を意味しましたか?もしそうなら、連結上の逆転の費用を負担する必要性がなぜ単一の旗への反対であるのかわかりません。これは実際に必要になるまで経費を遅らせるだけだと思いますか? – Alan
@Alan、 '<>'は '(<>):: Monoid a => a - > a - > a'の関数か' Semigroup'クラスのメソッドのいずれかです(ベースライブラリのバージョンに依存します)。同様の署名。 Haskellの一般的なコミュニティでは '><'より、 '(<>)=(><)'の場合はもっと広く知られています。費用が必要になるまで遅らせることは良いことですが、パフォーマンスを予測するのが難しく、多くの場合悪いこともあります。実際には、私は多くのシーケンス操作を自分の仕事よりも*熱心にこれに対処するように働いており、ベンチマークのパフォーマンスをかなり向上させてきました。 – dfeuer
さてあなたは
data S a = S { forward :: Seq a , backward :: Seq a }
を定義し、これはそれぞれのコストを倍増
forall a :: Type, s :: S a : reverse (forward s) == backward s .
という不変ですべての操作を実装することができ一定時間はreverse
となる。
はい、可能です。
しかし、これにより、すべてのルックアップに小さな値段が追加されます(最初にフラグをチェックする必要があります)。また、reverse
を使用するユーザーにのみ支払いが行われます。この後者のグループはおそらく小さいと判断された。タイプに適切なフラグを投げることはクライアント側で行うことができるので、はではなく、すべての関数を使用するたびにライブラリでこの値段を支払うことになります。代わりに、reverse
をたくさん呼びたいプログラマーは、望むのであればこのパフォーマンスのトレードオフの選択肢を作ることを余儀なくされます。これは私には完全に賢明です。
"最初にフラグをチェックする必要があります!"各要素ではなく(関数呼び出しごとに1回だけ)、 '><' operationは構造全体を再構築する必要があります – josejuan
><
連結がペナルティなしでxs >< reversed ys
の連結を認めている場合は、O(1)
で完了すると思います(フィンガーツリー構造に何らかのハックが必要です)。すべての操作は逆の対応(例えばtakeWhileL
〜takeWhileR
)を持っているか、O(n)
取るData.Sequenceに探し
; ><
操作を除いて(または最悪を。例えばzip
はseq1
ときn1<n2
などを逆にし、O(min(n1,n2))
を取ります)。
いずれにしても、xs >< ys
は、最悪の場合(4つの可能なケースのうちの2つ)としてO(min(|xs|,|ys|))
になります。これは実際にはO(n)
より少し優れています(ユニークな方向への正規化と反転が必要です)。
その後、質問は次のとおりです。
はO(min(|xs|,|ys|))
より良いxs >< reversed ys
を行うことができますか?
(理想的にO(log(min(|xs|,|ys|)))
)もちろん
、あなたが><
操作を使用しない場合は、逆の操作を取るO(1)
(例えば使用が左または右に対応するときチェックするためにフラグを使用)。
一方、逆順シーケンスのパフォーマンスを連結することが重要な場合は、おそらく他の最適な構造が存在するか、または@d8d0d65b3f7cf42 strategyと考えることができます。
私は魔法のハックはありません追加します。追加シーケンスは、左側のシーケンスの左側と右側のシーケンスの右側を取り、残りのセグメントを再帰的にマッシュして中央を形成することで動作します。あなたがそれぞれの左側を取って1つを反転させると、再帰が進むにつれて、中間のマッシングが次第に高価になります。 – dfeuer
これは、私が 'ハック'と言った理由です。連結の逆を避けるための1つの愚かなハックは、逆順のそれぞれの連結のためにシーケンスのシーケンス(実際にはツリー)かもしれません。逆の操作は償却されます( 'O(n)'操作が要求されるまで)、次の操作( 'index'など)は' O(log t * log n) 'の代わりに' (t * n)) 'tは保留中の連結で、' n'は平均トランクサイズです。ハックはマジックではありません... – josejuan
私の愚かなハックはあなたのレスポンスに書かれています! xD xD:P – josejuan
- 1. なぜO(n * logn)ではなくTreeSet Iteration O(n)ですか?
- 2. バイナリ検索はO(log n)かO(n log n)ですか?
- 3. なぜ配列挿入の時間複雑さはO(n)で、O(n + 1)ではないのですか?
- 4. 複雑さO(log(n))はO(sqrt(n))と等価ですか?
- 5. O(n)vs O(n^2)
- 6. なぜ最大合計サブアレイはブルートフォースO(n^2)ですか?
- 7. ブルートフォースポイントの最も近いペア。なぜO(n^2)ですか?
- 8. なぜこのO(n^2)ソリューションはO(n)ソリューションより速く動作するのですか?
- 9. f(n)= 1000n + 4500lgn + 54n O(n)ですか?
- 10. O(log n)は常にO(n)よりも速いですか
- 11. ログ(O(n * log(n)))は何ですか?
- 12. log(n!)= O((log(n))^ 2)ですか?
- 13. O(N)Oまで(LOGN)
- 14. T(n)= 2T(n/2)+ O(n)からO(nlogn)を得る方法
- 15. O(n^2 * log(n))とO(n^3)どちらが大きいですか?
- 16. なぜボトムの複雑さはO(n^3)でないのですか
- 17. O(m + n)かO(mlgn)が良いか
- 18. O(n)とO(log(n))の違い - これはより良く、O(log(n))は正確に何ですか?
- 19. このアルゴリズム(n^2)*(n^2 + 1)/ 2(つまりO(n/4))の実行時間はなぜですか?
- 20. O(n)
- 21. ListBox.FindString最悪の場合のランタイムは何ですか? O(n)、O(n log n)、O(1)?
- 22. このプログラムのBig-OはO(N^2)ですか?
- 23. 可能な説明(N!)= O(NLG(N))
- 24. 漸近分析では、 - O(f(n)+ g(n))= O(max {f(n)、g(n)})
- 25. O(1)、O(n log n)、O(log n)の複雑さを持つアルゴリズムの例
- 26. なぜ、ハートビートが伝播するのにO(ログN)時間かかります
- 27. O(n)ソートアルゴリズム
- 28. O(n * log n)の仕事をし、O(n^2)の仕事をするコードの複雑さは何ですか?
- 29. 証明Θ(n)+ O(n^2)≠Θ(n^2)
- 30. すべてのn、O(1)がO(n)よりも速い場合、O(1)上でO(n)を選択しますか?
それは可能ですが、そのフラグを運ぶために構造を拡張する必要があります。明らかに、Data.Sequenceの保守担当者は、それが価値がないと判断しました。 – Cubic
私はそれが必要な場合、私はそのようなカスタムフラグを運ぶ 'Seq'変種を書くだろう。 – chi
ほとんどのユースケースでは、追加のフラグの管理が導入するパフォーマンスのオーバーヘッドについては満足できません。 'Seq'をそれが何であるかにしましょう。あなたが必要とするものは、その上に単純なラッパーです。私たちは明確に分離可能な2つの抽象化を持っています。 –