如何确保从Data.Vector中分摊O(n)连接?

时间:2011-10-27 09:19:50

标签: haskell vector amortized-analysis

我有一个应用程序,其中使用Vector作为代码的一部分是有效的。但是,在计算过程中我需要跟踪一些元素。我听说你可以从Data.Vectors获得O(n)摊销连接(通过通常的数组增长技巧),但我认为我做得不对。所以我们假设我们有以下设置:

import Data.Vector((++),Vector)
import Prelude hiding ((++))
import Control.Monad.State.Strict

data App = S (Vector Int)

add :: Vector Int -> State App ()
add v1 = modify (\S v2 -> S (v2 ++ v1))

在这种情况下,add是否以摊销的O(n)时间运行?如果没有,我如何让add这样做(我需要在状态中存储(forall s. MVector s Int)吗?)。是否有更有效的方式来实施add

1 个答案:

答案 0 :(得分:2)

我也不太了解矢量库,所以我必须坚持一般原则。对它进行基准测试,运行一系列类似于您在应用程序中所期望的添加,并查看您获得的性能。如果它“足够好”,很棒,坚持使用简单的代码。如果没有,在将(forall s. MVector s Int)存储在状态(你不能直接,元组不能保存forall类型,所以你需要包装它)之前,尝试通过转换为改进添加行为可变的向量并在冻结之前执行连接以再次获得不可变向量,大致

add v1 = do
    S v2 <- get
    let v3 = runST $ do
                m1 <- unsafeThaw v2
                m2 <- unsafeGrow m1 (length v1)
                -- copy contents of v1 behind contents of v2
                unsafeFreeze m2
    put (S v3)

您可能需要在那里插入一些严格性。但是,如果unsafeGrow需要复制,则不能保证摊销的O(n)行为。

您可以通过

获得摊销的O(n)行为
  1. 在状态中存储已用插槽的数量
  2. 如果新的矢量最终适合自由空间,解冻,复制,冻结而不会增长
  3. 如果它不适合自由空间,则增长至少2倍,以保证每个元素平均最多复制两次