Recursion tends to be more writable and readable than iteration
A factorial function isn't really complex enough for you to see the advantages of recursion, but something like quick sort will.
Quick sort
First let's review what quicksort does:
it chooses a random value from the table and makes this the partition
it separates the values into those smaller than the partition and those bigger than the partition
it sorts those sub tables
it combines the smaller table, the partition then the bigger table
Implementation
Some code that I write will just be a port of some Haskell code so it will not exactly be the most performant. The Haskell code will be shown on top.
Recursive implementation
local function quickSort(t)
if #t == 0 then
return {}
end
local partition = table.remove(t)
local smaller = {}
local bigger = {}
for i = 1, #t do
local val = t[i]
table.insert(val < partition and smaller or bigger, val)
end
smaller = quickSort(smaller)
bigger = quickSort(bigger)
table.insert(smaller, partition)
for i = 1, #bigger do
table.insert(smaller, bigger[i])
end
return smaller
end
This implementation can be explained in a few sentences.
Quicksort on an empty table will yield an empty table because an empty table is already sorted.
If the table is not empty then get a partition from the table and separate values into those smaller than the partition and those bigger than the partition. Sort those sub tables and combine them all together.
This implementation makes sense, it's intuitive and it is easy to reason about. Now let's look at an iterative implementation
Iterative
local function newStack()
return {
pop = table.remove,
push = table.insert
}
end
local function swap(t, i, j)
t[i], t[j] = t[j], t[i]
end
local function partition(arr, p, s, e)
local l = s
local h = e - 1
local pivot = arr[p]
swap(arr, p, e)
while l < h do
if arr[l] < pivot then
l = l + 1
elseif arr[h] >= pivot then
h = h - 1
else
swap(arr, l, h)
end
end
local idx = h
if arr[h] < pivot then
idx = idx + 1
end
swap(arr, e, idx)
return idx
end
local function quickSort(arr)
local stack = newStack()
stack:push(1)
stack:push(#arr)
while #stack > 0 do
local e, s = stack:pop(), stack:pop()
if not (e - s < 2) then
local p = math.floor(s + (e - s)/2)
p = partition(arr, p, s, e)
stack:push(p + 1)
stack:push(e)
stack:push(s)
stack:push(p)
end
end
end
It's a big mess, it doesn't make sense and its confusing. This is the explanation provided by Stack Overflow
Push the range (0...n) into the stack
Partition the given array with a pivot
Pop the top element.
Push the partitions (index range) onto a stack if the range has more than one element
Do the above 3 steps, till the stack is empty
Sure, if you look at the code long and hard enough maybe you'll see it looking like that procedure explain above, but it's definitely harder to understand than the recursion code.
1 comment
ok