ОК, я думаю, что нашел один способ сделать это:
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 передаются по ссылке (верно?), так что, возможно, это улучшение, в конце концов.(Пожалуйста, поправьте меня, если я ошибаюсь!)