Учитывая направленное дерево T с переменным числом дочерних элементов на узел, я хотел бы найти путь размером PATH_SIZE из «хороших» узлов, начиная с root.Javascript: обход DFS для направленного дерева с участием ввода-вывода
у каждого узла есть метод isGood()
и метод getChildren()
, который работает должным образом.
Простой DFS рекурсивные решения будет выглядеть следующим образом: (пожалуйста, поправьте меня, если я ошибаюсь)
function findGoodPath(node, depth){
if(!node.isGood()){
return null;
} else if (depth==PATH_SIZE){
return [node];
}
var children = node.getChildren();
for (var i=0; i<children.length; i++){
var result = findGoodPath(children[i], depth+1);
if (result){
return result.concat([node]);
}
}
return null;
}
Вызов findGoodPath(root, 1)
должен найти результат, если таковой существует.
В настоящее время для проблема: метод объекта узла - это, по сути, метод асинхронного ввода-вывода за кулисами. он ничего не возвращает и ожидает один аргумент обратного вызова для обработки возвращенных детей.
Модифицированный раствор кода (который НЕПРАВИЛЬНО) может выглядеть следующим образом:
function findGoodPath(node, depth){
if(!node.isGood()){
return null;
} else if (depth==PATH_SIZE){
return [node];
}
node.getChildren(function(children){
for (var i=0; i<children.length; i++){
var result = findGoodPath(children[i], depth+1);
if (result){
return result.concat([node]);
}
}
});
}
Это решение не будет работать: все методы GetChildren детей одного узла будет называться сразу, так он фактически выполнит BFS. и, что еще хуже, операторы return связаны с анонимной функцией обратного вызова и будут выполняться после завершения функции закрытия.
Понятно, что существует необходимость в каком-то механизме управления потоком. Какое простое и элегантное решение этой проблемы?
ОБНОВЛЕНИЕ: Я принял ответ Себастьяна, так как он решает эту проблему с рекурсией, вот как я представил вопрос. Я также опубликовал ответ, в котором используется цикл async'swhilst, это то, что я использовал. Себастьян был достаточно любезен, чтобы сравнить эти два метода: here.(спойлер: производительность одинакова)
Спасибо Sebastien, замечательные замечания! –
мой плохой, конечно, функция должна иметь аргумент обратного вызова. Нефункциональный образец кода был просто для демонстрации некоторых проблем, превратив их в async. Я посмотрю на это утром, но мое текущее направление - перейти к нерекурсивному решению, а затем использовать функции из js async library для управления потоком. Сочетание асинхронных функций и рекурсии - хороший вызов, но я боюсь, что он создает не поддерживаемый код (по крайней мере для меня). –
Правда! Но быть в состоянии сделать это асинхронно, было бы очень эффективно, и это, безусловно, хорошая задача :) –