为什么在这种情况下使用数据构造函数和函数比使用字符串和Map要慢?
编辑:请注意我对Rotsor答案的第二次评论,它解释了为什么我接受了nulvinges的回答。
慢慢跑:
module Main where
import qualified Data.List as List
main :: IO ()
main = do
print $ conspire fabFive fabFive
-- here i actually have 80 constructors
data Eris = Hera | Athene | Aphrodite | Paris | Helene
deriving (Ord, Eq, Show, Read, Enum, Bounded)
fabFive = [minBound..maxBound] :: [Eris]
conspire :: [Eris] -> [Eris] -> [Eris]
conspire [Hera] [Hera] = [Hera, Athene]
...
conspire [Hera] [Helene] = [Athene, Aphrodite, Paris]
...
conspire [Helene] [Helene] = [Hera]
conspire [a] (b:bs) =
List.union (conspire [a] [b]) (conspire [a] bs)
conspire (a:as) ls =
List.union (conspire [a] ls) (conspire as ls)
运行得更快:
module Main where
import qualified Data.Map as Map
import qualified Data.Set as Set
main :: IO ()
main = do
print $ conspire (Set.fromList fabFive) (Set.fromList fabFive)
fabFive = [ Hera, Athene, Aphrodite, Paris, Helene ]
conspire :: Set.Set String -> Set.Set String -> Set.Set String
conspire set1 set2 = Set.fold Set.union Set.empty $ Set.map
(\x -> Set.fold Set.union Set.empty $ Set.map
(\y -> conspiracy Map.! (Set.singleton x, Set.singleton y))
set2
)
set1
conspiracy = Map.fromList
[ ( (Set.singleton "Hera" , Set.singleton "Hera" )
, Set.fromList [ "Hera", "Athene" ]
)
...
, ( (Set.singleton "Hera" , Set.singleton "Helene" )
, Set.fromList [ "Athene", "Aphrodite", "Paris" ]
)
...
, ( (Set.singleton "Helene" , Set.singleton "Helene" )
, Set.fromList [ "Hera" ]
)
]
答案 0 :(得分:4)
由于List.nub
函数,您的第一个版本运行缓慢,效率非常低。它在O(N^2)
时间内工作,N
是列表的大小。对于大nub
,其他所有内容都将由N
支配。
答案 1 :(得分:-1)
Map创建一个O(1)的散列映射,但是使用函数你必须检查每个条件。
编辑:这实际上是错误的。 Map是一个大小平衡的二叉树,但这应该会导致O(logn)复杂性,而函数必须检查每个组合,因此具有O(n)复杂度。
记住模式匹配的工作原理:
f 0 = 0
f i = 1+f (i-1)
是语法糖:
f i = if i == 0
then 0
else 1+f (i-1)
您正在进行O(n)比较,以找到您要执行的功能。
使用Map,它在二叉树中进行搜索,只需进行O(logn)比较。