【问题标题】:What's the difference between `ImmutableSortedSet` and fsharp `Set`?`ImmutableSortedSet` 和 fsharp `Set` 有什么区别?
【发布时间】:2013-04-19 10:44:07
【问题描述】:

BCL has introduced a group of Immutable Collections

我想知道ImmutableSortedSet 和原生 FSharp Set 有什么区别?似乎两者的性能特征相似。我还在某处看到SortedSet 被实现为红黑树,所以我猜ImmutableSortedSet 也是如此。

fsharpmap的内部实现是什么?是这里声明的Red Black Tree 还是这里发现的AVL tree?

此外,为什么 MSDN 文档没有明确说明图书馆馆藏的实际数据结构是什么?我知道这些是实现细节并且即将改变。我的观点是,如果他们不想将库数据类型绑定到某种类型的众所周知的数据结构,他们至少应该提供所有方法性能特征在复杂性方面的摘要?

【问题讨论】:

    标签: c# .net data-structures f# binary-search-tree


    【解决方案1】:

    我想知道 ImmutableSortedSet 和原生 FSharp Set 有什么区别?

    它们通常非常相似。主要区别在于 F#Set 支持快速集理论运算(并、交和差)。

    这是一个简单的 F# 程序,用于衡量一些常见操作的性能:

    open System.Collections.Immutable
    
    while true do
      do
        let timer = System.Diagnostics.Stopwatch.StartNew()
        let cmp = LanguagePrimitives.FastGenericComparer<int>
        let mutable s1 = ImmutableSortedSet.Create<int>(cmp)
        let mutable s2 = ImmutableSortedSet.Create<int>(cmp)
        for i in 1..1000000 do
          s1 <- s1.Add i
        for i in 1000000..2000000 do
          s2 <- s2.Add i
        printfn "BCL ImmutableSortedSet: add in %fs" timer.Elapsed.TotalSeconds
        timer.Restart()
        for _ in 1..10 do
          for i in 1..1000000 do
            ignore(s1.Contains i)
        printfn "BCL ImmutableSortedSet: contains in %fs" timer.Elapsed.TotalSeconds
        timer.Restart()
        let s = s1.Union s2
        printfn "BCL ImmutableSortedSet: union in %fs" timer.Elapsed.TotalSeconds
    
      do
        let timer = System.Diagnostics.Stopwatch.StartNew()
        let mutable s1 = Set.empty
        let mutable s2 = Set.empty
        for i in 1..1000000 do
          s1 <- s1.Add i
        for i in 1000000..2000000 do
          s2 <- s2.Add i
        printfn "F# Set: %fs" timer.Elapsed.TotalSeconds
        timer.Restart()
        for _ in 1..10 do
          for i in 1..1000000 do
            ignore(s1.Contains i)
        printfn "F# Set: contains in %fs" timer.Elapsed.TotalSeconds
        timer.Restart()
        let s = Set.union s1 s2
        printfn "F# Set: union in %fs" timer.Elapsed.TotalSeconds
    

    在我的机器上,我得到:

             BCL ImmutableSortedSet  F# Set
    add                2.6s          3.0s
    contains           2.1s          1.9s
    union              1.1s          0.00004s
    

    因此,F# Set 的构建速度稍慢,搜索速度稍快,但对于集合论并集运算来说要快几个数量级。

    fsharp map的内部实现是什么?是此处声称的红黑树还是此处发现的 AVL 树?

    正如您的两个链接所述,F# 使用 AVL 树。

    这实际上与上述性能数据相关。 AVL 树包含每个分支中子树的最大高度,因此允许重新平衡子树而无需检查整个子树。相比之下,红黑树在每个分支中都包含一位数据,因此重新平衡子树需要遍历整个树,这会逐渐变慢。用外行的话来说,两个相同大小的非重叠集合的并集只需要创建一个包含两个现有树的新分支。请注意,BCL API 中的Union 甚至无法表达这一点:它处理的是抽象的IEnumerable,而不是具体的集合。

    此外,为什么 MSDN 文档没有明确说明图书馆馆藏的实际数据结构是什么?我知道这些是实现细节并且即将改变。我的观点是,如果他们不想将库数据类型绑定到某种类型的众所周知的数据结构,他们至少应该提供所有方法性能特征在复杂性方面的摘要?

    我同意文档中的复杂性会很好。

    【讨论】:

      【解决方案2】:

      F# Set 和 Map 类型使用 AVL 树实现。

      我不了解 MSDN 文档,您必须向 F# 团队询问 :)

      在任何情况下,红黑树和 AVL 树的主要操作具有相同的计算复杂度。在实践中,它们具有不同的性能特征,可能会导致您为特定应用程序选择一种或另一种——红黑树具有更快的插入/删除速度,因为它们不需要对树进行尽可能多的重新平衡,而是检索由于它为插入/删除执行的额外平衡,在 AVL 树中更快。我想这就是为什么为 F# Map 和 Set 实现选择 AVL 树的原因 - Map/Set 通常创建一次(即不修改)然后重复查询。

      https://en.wikipedia.org/wiki/Red%E2%80%93black_tree

      https://en.wikipedia.org/wiki/AVL_tree

      【讨论】:

      • “我想这就是为什么选择 AVL 树用于 F# Map 和 Set 实现的原因。”我认为同样的原因也应该适用于 BCL 中的不可变集合。
      猜你喜欢
      • 2011-07-05
      • 2021-11-25
      • 2016-08-08
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 2023-02-14
      相关资源
      最近更新 更多