好的,我想我找到了一种方法:
function combinations (array, m)
local dropfirst = function (array)
return {table.unpack(array, 2, #array)}
end
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (sequence, m, prefix, queue)
local n = #sequence
local newqueue
if n >= m then
if m == 0 then
print(table.unpack(prefix))
else
local deleted = dropfirst(sequence)
if n > m then
newqueue = append(queue, {deleted, m, prefix})
else
newqueue = queue
end
return _combinations(deleted, m - 1,
append(prefix, sequence[1]),
newqueue)
end
end
if #queue > 0 then
newqueue = dropfirst(queue)
local newargs = append(queue[1], newqueue)
return _combinations(table.unpack(newargs))
end
end
_combinations(sequence, m, {}, {})
end
我认为这个版本是尾递归的。不幸的是,它并没有像我原来的非尾递归版本那样以良好的顺序打印出结果(更不用说增加的代码复杂性),但不能拥有一切!
编辑:好吧,不,一个可以拥有一切!下面的版本是尾递归的,并且以与原始非尾递归版本相同的顺序打印其结果:
function combinations (sequence, m, prefix, stack)
prefix, stack = prefix or {}, stack or {}
local n = #sequence
if n < m then return end
local newargs, newstack
if m == 0 then
print(table.unpack(prefix))
if #stack == 0 then return end
newstack = droplast(stack)
newargs = append(stack[#stack], newstack)
else
local deleted = dropfirst(sequence)
if n > m then
newstack = append(stack, {deleted, m, prefix})
else
newstack = stack
end
local newprefix = append(prefix, sequence[1])
newargs = {deleted, m - 1, newprefix, newstack}
end
return combinations(table.unpack(newargs)) -- tail call
end
它使用以下辅助功能:
function append (sequence, item)
local copy = {table.unpack(sequence)}
copy[#copy + 1] = item
return copy
end
function dropfirst (sequence)
return {table.unpack(sequence, 2, #sequence)}
end
function droplast (sequence)
return {table.unpack(sequence, 1, #sequence - 1)}
end
例子:
> combinations({1, 2, 3, 4, 5}, 3)
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
具有讽刺意味的是,这个版本通过实现自己的堆栈来实现尾递归,所以我不确定它最终是否比非尾递归版本更好......再说一次,我猜函数的 stack 确实存在在堆中(对吗?),因为 Lua 的表是通过引用传递的(对吗?),所以也许这毕竟是一种改进。 (如果我错了,请纠正我!)