提高关联列表生成的复杂性

时间:2014-11-12 00:17:52

标签: haskell time-complexity

我目前有一份表格清单:

[(foo, bar), (foo, baz), (qux, quux)]

我想将其转换为表单列表:

[(foo, [bar, baz]), (qux, [quxx])]

在我的实际用例中,该列表包含大约100万个这些元组。

目前,我正在通过以下方式解决这个问题,虽然它完全是纯粹的,没有副作用,但也是(据我所知)O(n^2)

import qualified Data.HashMap.Strict as M
foo xs = M.fromListWith (++) $ xs

有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

fromListWith算法has an O(n*log n) time complexity。没有其他限制,这是你能得到的最好的。这个想法是你需要遍历列表(O(n))和foreach元素插入(并检查重复)哈希中的键(O(log(n)))。

通过其他约束和更大的空间复杂性,您可能能够实现线性复杂性。例如,如果键的范围是“紧凑”而键是整数,那么您可以使用矢量/数组,并且可能在空间方面支付更多,但获得O(1)查找和插入。

答案 1 :(得分:1)

不,你没事,除了你的实施中的一个小错误[1]。正如杰弗里指出的那样,fromListWith具有 O(n log n)的复杂性,这非常好。

您可能遇到的潜在问题是附加,如果所有键都相同并且您附加到每个列表的末尾,则可能是 O(n ^ 2)。然而,一个小实验显示

data Tree a = Branch (Tree a) (Tree a) | Leaf a
   deriving (Show)

ghci> M.fromListWith Branch [(1, Leaf 1), (1, Leaf 2), (1, Leaf 3)]
fromList [(1,Branch (Leaf 3) (Branch (Leaf 2) (Leaf 1)))]

fromListWith将新元素作为组合函数的第一个参数,因此您将前置( O(1))而不是追加(这是 O(n)),所以你可以在那里。

[1]:在传递给M.fromListWith之前,您忘记从值中制作单例列表。