Below are two slightly different methods for listing all lexicographic permutations of N objects. I can't understand why the first method works fine for smallish N, but fails above a certain limit and results in 'stack overflow'. The second method; however, works just fine up to my tested limit of 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.
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 .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.