简体   繁体   English

为什么这些Ruby方法之一会导致“堆栈溢出”,而另一个却没有呢? (排列算法)

[英]Why does one of these Ruby methods result in 'stack overflow' but the other doesn't? (Permutations Algorithm)

Below are two slightly different methods for listing all lexicographic permutations of N objects. 下面是列出N个对象的所有字典排列的两种略有不同的方法。 I can't understand why the first method works fine for smallish N, but fails above a certain limit and results in 'stack overflow'. 我不明白为什么第一种方法对于较小的N可以很好地工作,但是在超过一定限制时失败,并导致“堆栈溢出”。 The second method; 第二种方法; however, works just fine up to my tested limit of 10**6. 但是,可以正常工作到我测试的极限10 ** 6。 Thanks in advance for your help and insight! 预先感谢您的帮助和见解!

$count = 0
$permutations = []

  def perms(array)  

     $permutations = array
     $count += 1

     if array.length <= 1
        return $permuations
     end

     i = (array.length - 2)
     until array[i] < array[i+1]
        i -= 1    
     end

     if i < 0
        return $permutations
     end

     j = (array.length - 1)
     until array[j] > array[i]
        j -= 1
     end

     array[i], array[j] = array[j], array[i]

     i += 1
     j = (array.length - 1)
     until j < i
        array[i], array[j] = array[j], array[i]
        i += 1
        j -= 1
     end

     while $count <= (10**6)-2
        perms(array)
     end
  end

  perms([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
  print $permutations

And here's the second method... 这是第二种方法

perm_limit = (10**6)

$count = 1 

def perms(array)
   if array.length <= 1
      return false
   end

   i = (array.length - 2)
   until array[i] < array[i+1]
      i = (i - 1)
   end

   if i < 0
      return false
   end

   j = (array.length - 1)
   until array[j] > array[i]
      j = (j - 1)
   end

   array[i], array[j] = array[j], array[i]

   i = (i + 1)
   j = (array.length - 1) 
   until j < i
      array[i], array[j] = array[j], array[i]
      i = (i + 1)
      j = (j - 1)
   end

   $count += 1 

   return true
end

array = [0,1,2,3,4,5,6,7,8,9]

while perms(array) == true
   if $count == perm_limit
      print array
   end
end    

Again, thanks. 再次感谢。

The first code sample you provide is a recursive function: 您提供的第一个代码示例是一个递归函数:

 while $count <= (10**6)-2
    perms(array)
 end

The function is calling itself, is calling itself, is calling itself until your stack overflows (everytime a function is called, space on stack is allocated). 该函数正在调用自身,正在调用自身,一直在调用自身,直到堆栈溢出(每次调用函数时,都会分配堆栈上的空间)。

Your second algorithm does not use a recursive function and so the depth of your stack is only one - your stack is not growing. 您的第二个算法不使用递归函数,因此堆栈的深度只有一个-堆栈没有增长。

For more information see "What is a stack overflow" . 有关更多信息,请参见“什么是堆栈溢出” The question is for Java, but the concept is the same for all stack-based languages. 问题是针对Java的,但是对于所有基于堆栈的语言,其概念都是相同的。

Recursive vs. iterative 递归与迭代

So why are we writing recursive functions/algorithms if they can overflow? 那么,如果递归函数/算法可能溢出,那为什么还要写它们呢? Because recursion can model some problems very nicely, and it can be easier to write a recursive algorithm (it's considered more "mathematically beautiful") than an iterative one. 因为递归可以很好地为某些问题建模,并且编写递归算法(被认为“数学上更漂亮”)比迭代算法容易。 If you know that your recursion depth won't be too deep, then recursion might be the preferred method. 如果您知道递归深度不会太深,则递归可能是首选方法。

On the other hand, an iterative algorithm is usually the preferred if you're worried about your stack space. 另一方面,如果您担心堆栈空间,通常首选迭代算法。 An iterative function can be easier or harder to write depending on how you model the problem. 根据对问题的建模方式,编写迭代函数可能更容易或更难。 All recursive functions can be converted to iterative functions. 所有递归函数都可以转换为迭代函数。

On a side note: there are some languages where recursion and stack space is not a problem. 附带说明:在某些语言中,递归和堆栈空间不是问题。 These languages may use "tail-calls" meaning the function is recursive, but instead of allocating new space on the stack, it simply re-uses the current function's stack space (and so the stack never grows). 这些语言可能使用“尾调用”,这意味着该函数是递归的,但是与其在栈上分配新的空间,它只是重复使用当前函数的栈空间(因此栈永远不会增长)。 You can read more here . 您可以在这里阅读更多内容

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM