如何尾递归实现组合?
我正在通过阅读Ierusalimschy的《Lua编程》(第4版)并做习题来自学Lua。练习6.5是
编写一个函数,它接受一个数组并打印数组中所有元素的组合。
通过这个简洁的语句,本书给出了一个提示,清楚地表明预期的是编写一个函数,该函数打印数组中的_m_元素的_C_(n,m)组合。
我实现了如下的“combinations”函数:
function combinations (array, m)
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (array, m, prefix)
local n = #array
if n < m then
return
elseif m == 0 then
print(table.unpack(prefix))
return
else
local deleted = {table.unpack(array, 2, #array)}
_combinations(deleted, m - 1, append(prefix, array[1]))
_combinations(deleted, m, prefix)
end
end
_combinations(array, m, {})
end
它可以正常工作,但不是尾递归的。
有人能给我展示一个尾递归的函数,该函数执行与上述'combinations'相同的操作吗?
(值得一提的是,我使用的是Lua 5.3。)
注意: 我意识到此习题并不要求该函数是尾递归的。这是我自己出于好奇而添加的要求。
编辑: 我稍微简化了函数,但去掉了一些不添加太多的嵌套函数。
有第三个选择,这个选择不会导致蛇咬自己的尾巴。虽然使用尾递归不会导致堆栈溢出,但是出于个人喜好,我避免使用尾递归。我使用 while 循环和一个保存每次迭代信息的堆栈。循环中,您从堆栈中弹出下一个任务,执行工作,然后将下一个任务压入堆栈。我认为这看起来更干净,更容易理解嵌套结构。
这是我将您的代码翻译成我的写法的方式:
function combinations(sequence, item)
local function append(array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local stack = {}
local node = { sequence, item, {} }
while true do
local seq = node[1]
local itm = node[2]
local pre = node[3]
local n = #seq
if itm == 0 then
print(table.unpack(pre))
elseif n < itm then
-- do nothing
else
local reserve = {table.unpack(seq, 2, #seq)}
table.insert(stack, { reserve, itm, pre })
table.insert(stack, { reserve, itm-1, append(pre, seq[1]) })
end
if #stack > 0 then
node = stack[#stack] -- LIFO
stack[#stack] = nil
else
break
end
end
end
您可以将这种 while 循环堆栈/节点技术用于几乎任何递归方法。以下是一个将其应用于打印深层嵌套表的示例:https://stackoverflow.com/a/42062321/5113346
我的版本使用您的输入示例产生相同的输出: 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。
如果适用于其他传递参数,请原谅我,因为我没有尝试解决练习的答案,而是只是按照您的原始帖子重新编写了代码。
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

我想我找到了一种方法来实现这个:
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)) -- 尾递归 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 的表是通过引用传递的(对吗?),所以也许这是一个进步(如果我错了,请纠正我!)。