Рекурсивные функции в Javascript и отслеживание глубины
Я пишу рекурсивную функцию в JS и возникли некоторые проблемы. Давайте начнем с этой самой основной функции:
function traverse(thing)
{
if (typeof traverse.depth == 'undefined')
traverse.depth = 1;
else
traverse.depth ++;
if (thing.child)
traverse(thing.child);
}
Так что это работает отлично, и depth
действует как статический var, но проблема в том, что в таком языке, как C, который имеет правильные статические vars, когда вы выходите из функции, эта переменная будет (якобы) уменьшаться, поэтому это истинная глубина. Если у меня есть три коробки, которые содержат три коробки, и каждая из них содержит три коробки и т. д. мы по сути углубляясь в самую глубокую, пока не останется детей, затем отступая на уровень к брату и сестре, и пересекая его детей. Проблема с вышеуказанным кодом заключается в том, что глубина продолжает увеличиваться и увеличиваться бесконечно, даже если глубина истины может быть только 3 или 4 от самого старшего предка до самого младшего ребенка. Если на каждом уровне есть 80 братьев и сестер, счетчик глубины взлетит до небес.
Как отслеживать истинную глубину в рекурсивных функциях JS?
5 ответов
не присоединяйте счетчик к функции. Счетчик является общим для всех рекурсивных вызовов, поэтому счетчик представляет количество вызовов функций вместо глубины рекурсии.
, когда depth
передается как отдельная переменная, счетчик показывает истинную глубину.
function traverse(thing, depth)
{
if (typeof depth == 'number')
depth++;
else
depth = 1;
if (thing.child)
traverse(thing, depth);
}
другим (и, возможно, более приятным) решением было бы использовать сильные стороны функционального программирования JS и использовать функцию высокого порядка, чтобы сохранить все связанные с глубиной домохозяйства вне основной функции. Рассмотрим, например, следующий классический пример:
function fac(n) {
if(n < 3)
return n;
return n * fac(n - 1);
}
мы хотим, чтобы этот сломал рекурсию, как только она будет глубже, чем заданное значение. Давайте закодируем обертку:
function wrapDepth(fn, max) {
var depth = 0
return function() {
if (++depth > max)
throw "Too much recursion"
var out = fn.apply(null, [].slice.call(arguments, 0))
depth--;
return out;
}
}
создайте обертку с максимальной глубиной = 20:
fac = wrapDepth(fac, 20)
и тест:
console.log(fac(10)) // 3628800
console.log(fac(100)) // Too much recursion
обратите внимание, что мы не делали никаких изменений в функции main fac
сам, но все же его глубина рекурсии теперь находится под контролем.
почему бы тебе просто не изменить сигнатуру функции, чтобы взять вещь и индекс? Поэтому вы бы назвали это так:
function traverse(thing, idx)
...
if (condition)
traverse(thing.child, ++idx)
просто добавить:
traverse.depth--;
прямо перед любыми операторами возврата. Так что
if(x === 5)
return thing;
станет:
if(x === 5){
traverse.depth--;
return thing;
}
и затем добавить traverse.depth--;
перед закрывающим }
функции.
Если я правильно понял, мне кажется, что вы хотите отслеживать глубину рекурсии.. но в вашем коде вы никогда не уменьшаете глубину по мере завершения 1 уровня в рекурсии.
Я пробовал простой код, и я думаю, что это то, что вы хотели,
HTML-код:
<div id="result"></div>
JS:
var result = document.getElementById('result');
var tmpArray = [1,2,3,4,5,6,7,8];
function depthTest() {
if (typeof depthTest.depth == 'undefined')
depthTest.depth = 0;
else
depthTest.depth++;
result.innerHTML += depthTest.depth;
if (typeof tmpArray[depthTest.depth] != 'undefined')
depthTest();
result.innerHTML += depthTest.depth;
depthTest.depth--;
}
depthTest(tmpArray);
выход:
012345678876543210