Ruby组合函数的阶复杂性

Ruby组合函数的阶复杂性,ruby,algorithm,big-o,complexity-theory,Ruby,Algorithm,Big O,Complexity Theory,在我的一个算法中,我使用Ruby的和方法。我必须讨论这个算法的复杂性。我在哪里可以找到有关其复杂性/实现的信息 我尝试过实现一个简单的“手工制作”函数,但Ruby函数似乎运行在几乎恒定的时间内 如果您能提供有关在何处查找的任何信息,我们将不胜感激。您可以在链接的相同页面上显示实现。将鼠标悬停在组合/排列方法的名称上,然后选择单击以切换源代码 您可以在主回购网站查看最新和不同版本的source: 您可以阅读array.c的修订历史,了解为什么/何时对组合/排列方法进行了任何更改。这可能会让您了解开

在我的一个算法中,我使用Ruby的和方法。我必须讨论这个算法的复杂性。我在哪里可以找到有关其复杂性/实现的信息

我尝试过实现一个简单的“手工制作”函数,但Ruby函数似乎运行在几乎恒定的时间内


如果您能提供有关在何处查找的任何信息,我们将不胜感激。

您可以在链接的相同页面上显示实现。将鼠标悬停在组合/排列方法的名称上,然后选择
单击以切换源代码

您可以在主回购网站查看最新和不同版本的source:

您可以阅读
array.c
的修订历史,了解为什么/何时对组合/排列方法进行了任何更改。这可能会让您了解开发人员所做的复杂性和设计选择


您甚至可以向源代码的某些贡献者询问他们为什么对方法进行XYZ更改的原因,他们可能/可能没有帮助。

Ruby语言规范中没有要求实现者保证某种算法复杂性的内容,当然,并没有任何东西会强制特定的实现

每个Ruby执行引擎都有自己的实现,它们的算法复杂度可能相同,也可能不同

例如,下面是
数组#组合的实现
,位于:

如您所见,它将委托给名为
Array#uuuuu permute_uuu
private
帮助器方法,该方法定义于:

def\uuu permute\uuu(num、perm、index、used和block)
#递归计算集合[0..n-1]中r个元素的置换。
#当我们有一个完整的数组索引排列时,复制这些值
#将这些索引转换为一个新数组并生成该数组。
#
#num:每个排列中的元素数
#perm:我们正在填充的数组(大小为num)
#索引:我们现在填写的是什么索引
#已使用:布尔数组:给定索引是否已使用
#
#注意:效率不如大num。
@总计.次do | i|
除非使用[i]
perm[index]=i
如果索引
干杯,我没注意到。不知道为什么我的问题被否决了。关于如何更好地表达这个问题有什么想法吗?我认为这个问题措辞正确。我不太确定好的,非常感谢你的回答。非常感谢。啊,很有趣。这也是一个很好的答案。有了这个和上面的C实现,我应该能够给出一个很好的描述。非常感谢您抽出时间。
def combination(num)
  num = Rubinius::Type.coerce_to num, Fixnum, :to_int
  return to_enum(:combination, num) unless block_given?

  if num == 0
    yield []
  elsif num == 1
    each do |i|
      yield [i]
    end
  elsif num == size
    yield self.dup
  elsif num >= 0 && num < size
    stack = Rubinius::Tuple.pattern num + 1, 0
    chosen = Rubinius::Tuple.new num
    lev = 0
    done = false
    stack[0] = -1
    until done
      chosen[lev] = self.at(stack[lev+1])
      while lev < num - 1
        lev += 1
        chosen[lev] = self.at(stack[lev+1] = stack[lev] + 1)
      end
      yield chosen.to_a
      lev += 1
      begin
        done = lev == 0
        stack[lev] += 1
        lev -= 1
      end while stack[lev+1] + num == size + lev + 1
    end
  end
  self
end
def permutation(num=undefined, &block)
  return to_enum(:permutation, num) unless block_given?

  if undefined.equal? num
    num = @total
  else
    num = Rubinius::Type.coerce_to num, Fixnum, :to_int
  end

  if num < 0 || @total < num
    # no permutations, yield nothing
  elsif num == 0
    # exactly one permutation: the zero-length array
    yield []
  elsif num == 1
    # this is a special, easy case
    each { |val| yield [val] }
  else
    # this is the general case
    perm = Array.new(num)
    used = Array.new(@total, false)

    if block
      # offensive (both definitions) copy.
      offensive = dup
      Rubinius.privately do
        offensive.__permute__(num, perm, 0, used, &block)
      end
    else
      __permute__(num, perm, 0, used, &block)
    end
  end

  self
end
def __permute__(num, perm, index, used, &block)
  # Recursively compute permutations of r elements of the set [0..n-1].
  # When we have a complete permutation of array indexes, copy the values
  # at those indexes into a new array and yield that array.
  #
  # num: the number of elements in each permutation
  # perm: the array (of size num) that we're filling in
  # index: what index we're filling in now
  # used: an array of booleans: whether a given index is already used
  #
  # Note: not as efficient as could be for big num.
  @total.times do |i|
    unless used[i]
      perm[index] = i
      if index < num-1
        used[i] = true
        __permute__(num, perm, index+1, used, &block)
        used[i] = false
      else
        yield values_at(*perm)
      end
    end
  end
end