我正在练习解决类的递归问题。
我正在解决此网站上的问题:http://www.w3resource.com/javascript-exercises/javascript-recursion-functions-exercises.php
我提到的问题是:写一个JavaScript程序来获取范围(x,y)中的整数。 示例:范围(2,9) 预期产出:[3,4,5,6,7,8]
在查看解决方案之前,我想出了这个:
var range = function (start, end) {
var result = [];
var accumulator = start;
var accumulate = function () {
accumulator++;
if (accumulator === end) {
return;
} else {
result.push(accumulator);
}
accumulate();
};
accumulate();
return result;
};
网站上的解决方案是:
var range = function(start_num, end_num)
{
if (end_num - start_num === 2)
{
return [start_num + 1];
}
else
{
var list = range(start_num, end_num - 1);
list.push(end_num - 1);
return list;
}
};
我的解决方案在技术上仍然是递归的吗?我最近在测验中得到了类似的答案,我被告知我的解决方案基本上是迭代的。
答案 0 :(得分:3)
虽然你使用递归,但你只需要以递归的形式写一个循环。
我将从纯粹的学术观点来回答这个问题。如果你想避免中间状态(result
)并使用纯粹的功能结构,我会像这样写它
function range(start, end) {
function recRange(current, end) {
if (current > end)
return [];
return [current].concat(recRange(current + 1, end));
}
return recRange(start + 1, end - 1);
}
console.log(range(2, 9));
// [ 3, 4, 5, 6, 7, 8 ]
如果你看到这里,我们在range
函数中创建一个新函数,它在每次迭代时递归地创建一个新数组(记住:这不是高性能代码,你可以简单地使用循环并完成这个问题有效。)
递归的基本条件是current < end
。一旦满足,递归就会停止,并返回一个空数组。在所有级别中,具有current
值的新数组与递归调用的结果连接在一起。因此,对呼叫的评估大致可以理解为
[3].concat(recRange(3 + 1, end));
[3].concat([4].concat(recRange(4 + 1, end)));
...
最后,当递归展开时,值将是这样的
[3].concat([4].concat([5].concat([6].concat([7].concat([8].concat([]))))))
[3].concat([4].concat([5].concat([6].concat([7].concat([8])))))
[3].concat([4].concat([5].concat([6].concat([7, 8]))))
[3].concat([4].concat([5].concat([6, 7, 8])))
[3].concat([4].concat([5, 6, 7, 8]))
[3].concat([4, 5, 6, 7, 8])
[3, 4, 5, 6, 7, 8]
,这将作为结果返回。
答案 1 :(得分:2)
我的解决方案在技术上仍然是递归的吗?
是。你正在使用尾递归;但是,由于没有任何参数传递给accumulate(),我可以看到为什么有人会说它基本上是迭代的。您可以使用循环轻松替换递归调用。递归算法通常利用堆栈。
由于Javascript的闭包,与其他语言(如C ++,Java或C#)相比,更难理解Javascript中的递归概念。
要理解递归,首先必须了解递归。 :)
答案 2 :(得分:2)
为了使您的解决方案递归,它应该返回一些值并以某种方式组合递归调用的结果以形成原始调用的返回值。
让我用一个例子来说明,通过修改你的解决方案:
var range = function (start, end) {
var accumulate = function (accumulator) {
if (accumulator === end - 1) {
return [accumulator]; // Stop condition
} else {
// Recursive block
var result = accumulate(accumulator+1); // recursive call
result.unshift(accumulator); // combine result
return result
}
};
return accumulate(start);
};
修改后的累积函数将返回一个单元素列表,用于停止条件,它处理的最简单的情况,累加器到达最后一个返回的值。
在示例range(2,9)
中,停止条件将返回[8]
。
然后在调用者中,递归块
var result = accumulate(accumulator+1);
result.unshift(accumulator);
return result
将获取列表[8]
,并预先提供当前值accumulator
(7
),因此它将返回[7,8]
。
...以及accumulator(7)
的来电者将收到[7,8]
并将值6
预先预付到列表中,以返回[6,7,8]
。
最后,对accumulator(2)
的原始调用将生成预期结果[2,3,4,5,6,7,8]
。