如何在Ruby中实现阵列集和排序集

时间:2014-11-05 17:45:43

标签: ruby

通常,数组实现为内存块,设置为哈希映射,排序集实现为跳过列表。 Ruby中的情况也是如此吗?

我试图在性能和内存占用方面评估Ruby中不同容器的使用

2 个答案:

答案 0 :(得分:7)

Arrays是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。 Ruby语言规范仅指定Ruby数组的行为,它没有指定任何特定的实现策略。它甚至没有指定任何强制或至少暗示特定实施策略的性能约束。

然而,大多数Rubyist对数组的性能特征有一些期望,这会强制实现不能满足它们的实现,因为没有人会实际使用它:

  • 插入,前置或附加以及删除元素具有O(n)的最坏情况步长复杂度和O(1)的最低情况下的最坏情况步骤复杂度
  • 访问元素的最坏情况步骤复杂度为O(1)
  • 遍历所有元素具有最坏情况的步骤复杂度O(n)

这意味着数组需要实现为具有指数调整大小的动态数组,否则无法满足这些性能保证。你可能逃脱了一个非常宽而浅的树,但AFAIK没有Ruby实现那样做。

这里是Rubinius's array implementation,我个人觉得最容易阅读所有Ruby实现。 (注意:只有基本要素是用C ++实现的,大多数数组方法都是用Ruby实现的,例如在kernel/common/array.rb中)。

SetSortedSet是stdlib中set库的一部分。 stdlib在Ruby实现之间基本没有共享(至少实际用Ruby编写的部分,很明显用其他语言编写的部分不能共享),而且由于Set是用Ruby编写的,所以在所有Ruby实现上都可以期待它。

Set实现为Hash,其中只使用了密钥,值只是true:请参阅Set#add in lib/set.rb

SortedSet由Red-Black-Tree支持,但没有在Ruby中实现。

答案 1 :(得分:2)

以前的答案实际上并没有涵盖SortedSet的表现。

  • 数组 - 用于按索引添加,删除和访问元素的O(1)
  • 哈希(使用哈希表) - O(1)(当然比数组大1)用于按键添加,删除和访问
  • Set - 由Hash实现,所以
  • SortedSet的:

因此,在阅读代码并使用计算每个比较方法调用的类手动测试之后,结果就是这里。 它试图加载' rbtree'模块并使用常规Set作为后备。

所以2个选项:

  1. RBTree可用,一切都很快,正如预期的那样,每次添加都是O(logN),首先是O(1),soeted_set.to_a是O(N)。
  2. RBTree不可用。它使用Set(下面的Hash)并在读取时重新排序。
  3. 来自Ruby 2.0.0 set.rb:

    def to_a
      (@keys = @hash.keys).sort! unless @keys
      @keys
    end
    

    意思是以下代码:

    X.times{ sorted_set << num; sorted_set.first }
    

    将是O(XNlog(N)),因为排序是近似Nlog(N)。

    所以基本上使用SortedSet而不确保RBTree可用是令人困惑和低效的,因为它在插入时没有使用它排序(二进制搜索)的事实。 因此,在这种情况下,使用普通的Set和array方法可能会更快。

    使用常规Set的相同示例:

    X.times{ set << num; set.min }
    

    将是O(XN)

    一句话,如果你需要SortedSet工作效率,还要添加&#39; rbtree&#39;到Gemfile。