Как правильно связывать ООП и рекурсию?
2. переделать рекурсию в цикл, и хранить данные на уровне метода
1. хранить данные на уровне объектаКакого конкретно?
2. переделать рекурсию в циклТо есть обычная рекурсия и ооп - не совместимы?
хранить данные на уровне методаЭто как?
Используй рекурсивный метод объекта, хранящего эти данные.
TYPE
B = OBJECT (A)
data: Data;
PROCEDURE Rec (...);
BEGIN
...
self.data := ...
...
Rec(...);
...
END Rec;
END;
То есть обычная рекурсия и ооп - не совместимы?Методы - процедуры, ассоциированные с типом данных, и использование таких процедур не ограничивает использование рекурсивных алгоритмов.
Вспомогательного.
> Это как?
в локальной переменной
То есть создавать объект результата, а рекурсивный вызов делать в виде метода этого объекта - так?
А можно пример на чем-нибудь более привычном (хотя мб я просто торможу и потом его пойму)7..
> Какого конкретно?Ты про объект результата?
Вспомогательного.
> Это как?Понял.
в локальной переменной
так тоже можно, но лучше создавать временный объект на время работы рекурсии
Чем же это лучше?
логически стройнее
Что он должен делать?
псевдокод такой рекурсии выглядит так:
результат recurse(начальные данные)
{
o = new ВспомогательныеОбъект(начальные данные);
o.Recurse;
return o.Result;
}
такое преобразование экономит память стека, а также время на копирование операндов
такое преобразование экономит память стекаНе очень понятно, за счет чего это происходит.
Да, параметры передавать не надо, зато при каждом вызове надо создавать ВспомогательныйОбъект.
Или это синглетон?
Кстати, какие-нибудь шаблоны на этот случай не предусмотрены случайно?
Жаль, интересно было бы посмотреть твой пример.
потому что нач. условия, и вспомогательные данные не пихаются в стек на каждой итерации рекурсии
> Да, параметры передавать не надо, зато при каждом вызове надо создавать ВспомогательныйОбъект.
на каком еще каждом вызове?
MODULE TmpM;
IMPORT TextMappers, TextModels, TextViews, Views;
TYPE
Node = POINTER TO RECORD
left, right: Node;
x: INTEGER
END;
Tree = RECORD
root: Node
END;
PROCEDURE (VAR t: Tree) Fill, NEW;
BEGIN
NEW(t.root); t.root.x := 2;
NEW(t.root.left); t.root.left.x := 3;
NEW(t.root.left.left); t.root.left.left.x := 7;
NEW(t.root.right); t.root.right.x := 5;
END Fill;
PROCEDURE (VAR t: Tree) Dump (VAR f: TextMappers.Formatter NEW;
(* In-order *)
PROCEDURE Rec (n: Node);
BEGIN
IF n # NIL THEN
Rec(n.left);
f.WriteInt(n.x);
Rec(n.right)
END
END Rec;
BEGIN
Rec(t.root)
END Dump;
PROCEDURE Do*;
VAR t: Tree;
f: TextMappers.Formatter;
m: TextModels.Model;
v: TextViews.View;
BEGIN
t.Fill;
m := TextModels.dir.New; f.ConnectTo(m);
t.Dump(f);
v := TextViews.dir.New(m); Views.OpenView(v)
END Do;
END TmpM.
После запуска TmpM.Do появляется окошко с текстом "7325"
f - это те самые данные.
На Java и C# должно быть аналогично.
Ведь он является объектом результата - o.Result.
Так в чем его отличие от объекта результата?
Ведь вызов Recurse у ВспомогательныеОбъект и вызов "результат recurse(начальные данные)" - это разные вызовы?
И как ты передаешь измененные начальные данные в очередной вызов?
Спасибо, посмотрю
процедурный подход:
ITreeNode[] Browse(ITreeNode root, Filter filter)
{
List<ITreeNode> nodes = new List<ITreeNode>
foreach (ITreeNode child in root.Childs)
{
nodes.AddRange(Browse(child filter);
if (filter(child
nodes.Add(child);
}
return nodes.ToArray;
}
в итоге мы постоянно пихаем в стек filter, на каждой итерации создаем список, а также постоянно заняты слиянием списков
через вспомогательный объект
ITreeNode[] Browse(ITreeNode root, Filter filter)
{
Browser browser = new Browser(root, filter);
browser.Browse(root);
return browser.Nodes.ToArray;
}
class Browser
{
public Browser(ITreeNode root, Filter filter)
{
this.root = root;
this.filter = filter;
}
ITreeNode root;
Filter filter;
public void Browse(ITreeNode node)
{
foreach (ITreeNode child in root.Childs)
{
Browse(child);
if (filter(child
Nodes.Add(child);
}
}
public List<ITreeNode> Nodes = new List<ITreeNode>
}
видно, что на каждой итерации нет передачи нач. условий (ссылки на filter вспомогательные данные/результат тоже не копируется.
за ОО-лоском потерялось главное
copy/cut/paste-ил - и за cut-ил лишнего.
ну и в 2 раза длиннее стало по сравнению с процедурным примером
не приспособлены, однако, кролики по деревьям лазать
на практике, чистые списки редко используются - соответственно конкатенация списков может быть довольно длительной операцией.
> ну и в 2 раза длиннее стало по сравнению с процедурным примером
это единственный критерий?
в данном примере, всего на всего приведено замыкание исходного процедурного примера.
алгоритмы оптимизации ФЯ делают обычно все тоже самое, получая такой же результат.
Оставить комментарий
durka82
Если рассматривать рекурсивные алгоритмы, результатом которых является одно число (например, вычисление выражения со скобками) - там все просто - рекурсивная ф-я возвращает один результат - число.А как быть, когда результат - некоторая структура данных, которая формируется в процессе работы рекурсии?
Например, если рассматривать алгоритм определения всех простых делителей числа, нужно ли, чтобы результатом рекуррентной функции было множество всех простых делителей, найденных для текущего делителя числа.
Или надо все таки формировать результат как параллельную рекурсии структуру данных?
Какой вариант правильнее? Или какие еще есть варианты?
Причем здесь ООП? Если писать эта на java/c++ - надо будет все это вписать в такой подход.
Как это лучше сделать?