【问题标题】:Complexity of lists in haskell in Data.mapData.map中haskell中列表的复杂性
【发布时间】:2013-09-15 08:16:37
【问题描述】:

抱歉,这似乎是一个显而易见的问题。

我正在创建列表的 Data.map {实际上是整数的元组和列表 (Integer, [(Integer, Integer)])},用于为 Dijkstras 和 Prims 等一些图形算法实现优先级队列 + 邻接列表,

Data.map 是使用二叉树实现的(我读过),所以我只想确认在执行映射操作时(我相信它们将是旋转),解释器不会对列表进行深拷贝,而只是浅拷贝列表的引用对吗?

我这样做是为了在 haskell 中实现一个 prims 算法,该算法将在 n = no 的 O(nlogn + mlogn) 时间内运行。顶点数,m = no。边缘,以纯粹的功能方式, 如果列表存储在优先级队列中,则该算法将在那个时候起作用。我在网上找到的大多数 haskell 实现都没有达到这种复杂性。

提前致谢。

【问题讨论】:

  • Haskell 本身并没有对此做出任何承诺,但我所知道的没有实现深度复制。

标签: list haskell map time-complexity


【解决方案1】:

您是正确的,每次创建新的Map 时都不会复制列表,至少在您使用 GHC 的情况下是正确的(其他实现也可能正确执行此操作)。这是纯函数式语言的优点之一:因为无法重写数据,所以不需要复制数据结构以避免在命令式语言中可能遇到的问题。考虑一下 Lisp 的这个 sn-p:

(setf a (list 1 2 3 4 5))
(setf b a)
; a and b are now both '(1 2 3 4 5).
(setf (cadr a) 0)
; a is now '(1 0 3 4 5).
; Careful though! a and b point to the same piece of memory,
; so b is now also '(1 0 3 4 5). This may or may not be what you expected.

在 Haskell 中,拥有像这样的可变状态的唯一方法是使用显式可变的数据结构,例如 State monad 中的某些东西(甚至这有点假装它(这是一件好事)) .这种潜在的意外内存重复问题在 Haskell 中是不可想象的,因为一旦你声明 a 是一个特定的列表,它现在和永远都是那个列表。因为它保证永远不会改变,所以对本应相等的事物重用内存是没有危险的,事实上,GHC 正是这样做的。因此,当您使用相同的值创建一个新的Map 时,只会复制指向值的指针,而不是值本身。

有关更多信息,请阅读the difference between Boxed and Unboxed types

【讨论】:

    【解决方案2】:

    1) IntegerInt

    2) 如果你有[(Integer, [(Integer, Integer)])]

    您不仅可以使用Data.Map 创建Map Integer [(Integer, Integer)],还可以使用Map Integer (Map Integer Integer)

    3) 如果您使用 Int 而不是 Integer,您可以使用更快的数据 - IntMapfrom Data.IntMap: IntMap (IntMap Int)

    4) 每种方法的复杂度都写在描述中: Data.IntMap.Strict 和这里 Data.IntMap.Lazy:

    map :: (a -> b) -> IntMap a -> IntMap b
    O(n). Map a function over all values in the map. 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-25
      • 1970-01-01
      • 2014-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      相关资源
      最近更新 更多