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