在一次采访中,他们让我“给出一些间接递归的实际应用”。我只是回答了直接递归和间接递归之间的区别。我用谷歌搜索,但仍然没有得到任何令人满意的答案。
欢迎提供有关此主题的任何信息。
答案 0 :(得分:5)
间接递归的一个明显例子是递归下降解析器。
举一个简单的例子,考虑语法如下:
expression = product (+|-) product
product = term (*|/) term
term = number | variable | '(' expression ')'
要使用递归下降解析器解析该语法,我们基本上创建一个函数来表示每个元素:
expression(input) {
product(input);
assert(operator(input) == '-' || '+');
product(input);
}
product(input) {
term(input);
assert(operator(input) == '/' || '*');
term(input);
}
term(input) {
if (next(input) == '(')
expression(input);
// ...
}
我显然在这里简化了许多,但希望总体思路出现:表达式由+
或-
组合的产品组成。产品由/
或*
组合的术语组成。术语是括号中的数字或变量或表达式。我们称一个函数来识别每个函数,所以当我们将括号中的表达式识别为术语时,我们使用间接递归 - expression()
- > product()
- > term()
- > expression()
。
答案 1 :(得分:2)
BTW,我知道它的名字是相互递归。
它可用于模拟有限自动机,但仅当语言实现尾调用优化时,这意味着当一个递归调用以仅由进一步递归调用组成的return语句终止时,该递归调用将重用当前堆栈帧。如果没有这种优化,相互递归很容易导致Stack Overflow(pun ... well: - )。
更明确地说,这是一个Lua脚本,它识别输入字符串中第一次出现字符串111
。每个函数表示有限自动机的状态,并且通过相互递归调用来模拟状态转换(Lua执行适当的尾调用优化,因此即使对于更长的输入字符串也不会发生堆栈溢出)。在C ++中,相同的技术不适用,因为标准(AFAIK)不能保证正确的尾调用优化。如果您不了解Lua,请将其视为伪代码(它具有相当的可读性,因为它具有类似Pascal的语法)。无论如何,您可以将代码剪切并粘贴到live demo。
function Init( input, pos )
if pos > #input then return 0 end
local bit = input:sub( pos, pos )
if bit == "0" then
return Got0( input, pos + 1 )
else
return Got1( input, pos + 1 )
end
end
function Got0( input, pos )
if pos > #input then return 0 end
local bit = input:sub( pos, pos )
if bit == "0" then
return Got0( input, pos + 1 )
else
return Got1( input, pos + 1 )
end
end
function Got1( input, pos )
if pos > #input then return 0 end
local bit = input:sub( pos, pos )
if bit == "0" then
return Got0( input, pos + 1 )
else
return Got11( input, pos + 1 )
end
end
function Got11( input, pos )
if pos > #input then return 0 end
local bit = input:sub( pos, pos )
if bit == "0" then
return Got0( input, pos + 1 )
else
print( "recognized 111 sequence at position " .. pos - 2 )
print( input )
print( (" "):rep( pos - 3 ) .. "^" )
return 1
end
end
Init( "1101101101110110101", 1 )