作用于长度为n的列表的排列

时间:2017-02-13 18:30:40

标签: algorithm haskell

在数学中,当我想重新排列长度为n的列表时,我将使用排列对列表进行操作。例如:

(1 2) * (x, y, z) = (y, x, z)
(1 n 2) * (v[1], v[2], ..., v[n]) = (v[n], v[1], ..., v[2])
perm * (v[1], v[2], ..., v[n]) = ( v[perm(1)], v[perm(2)], ..., v[perm(n)] )

我如何在Haskell中执行此操作?

1 个答案:

答案 0 :(得分:2)

我会使用输入排列来构建从旧索引到新索引的映射。

import Prelude hiding ((*))
import qualified Data.Map as M

infixr 5 * -- right-associative so we can compose permutations conveniently

(*) :: [Int] -> [a] -> [a]
perm * xs = zipWith (\i _ -> xs !! M.findWithDefault i i ixMap) [0..] xs
    where ixMap = M.fromList (zip perm (drop 1 perm ++ take 1 perm))

您可以在ghci提示符中看到它的运行情况(尽管在编程中它通常使用基于0而不是基于1的索引):

> [0,1] * "xyz"
"yxz"
> [0,4,1] * "abcde"
"eacdb"

这需要O(n ^ 2 log m),其中n是xs的长度,m是perm的长度。您可以通过从(!!)切换到M.lookup将索引编入xs,将其减少到O(n log(nm))。