* O(n)*“forward”Data.Vector`permute`函数

时间:2011-07-18 10:40:38

标签: haskell

Data.Vector API提供了一个高效的backpermute函数,该函数基本上将索引映射σ - 向量应用于向量v,即v'[j] = v[σ[j]]

或者以list-syntax表示(为简单起见):

backpermute :: [Int] -> [a] -> [a]
backpermute σ v = map (v !!) σ

如果!!具有 O(1)复杂度(我假设为Data.Vector),那么 O(n)复杂度可能会有所不同。现在我想要反向“前向”permute操作(或者反转σ - 向量本身的函数),即类似(再次在列表语法中):

permute :: [Int] -> [a] -> [a]
permute σ = map snd . sortBy (comparing fst) . zip σ

invperm :: [Int] -> [Int]
invperm σ = permute σ [0..]

唉,由于sortBy,上面的代码不是 O(n)。但由于σ被假定为[0..] permute前缀的排列,因此应将其表示为{em> O(n)算法{{1} API。

那么,我怎样才能实现高效的 O(n) Data.Vector(或者 O(n) permuteinvperm API?

2 个答案:

答案 0 :(得分:6)

因此permute应该采用索引向量和值向量并创建一个新向量,以便每个值都存储在相应的索引中,即v'[σ[j]] = v[j],{backpermute的倒数1}}。

据我所知,Data.Vector中没有用于构建索引值对的新Vector的函数,但是有一个更新现有向量的函数,即  update :: Vector a -> Vector (Int, a) -> Vector a。它的运行时是 O(m + n),其中 m 是向量的大小, n 是更新的数量。

还有变体update_ :: Vector a -> Vector Int -> Vector a -> Vector a,它采用两个向量而不是对向量。完善。现在我们只需要一个初始向量来“覆盖”这些值。假设σ是有效的排列,所有项目都将更新,因此任何类型和长度与v相同的向量都可以,因此我们可以重用v

permute :: Vector Int -> Vector a -> Vector a
permute σ v = update_ v σ v

由于σ的长度与v相同,因此运行时为 O(n)

更安全的选择是使用最低值向量。这样,如果您尝试读取σ中没有索引的项目而不是默默地得到错误的结果,您将收到错误。

permute σ v = update_ (replicate (length v) undefined) σ v

答案 1 :(得分:6)

Monadic初始化,也许?

invSigma :: Vector Int -> Vector Int
invSigma s = create $ 
             do v <- new n
                zipWithM_ (write v) s (enumFromN 0 n)
                return v
  where n = V.length s