懒惰递归函数的非递归等价
本文关键字:递归 递归函数 | 更新日期: 2023-09-27 18:22:14
考虑以下代码在Rose Tree上实现深度优先搜索:
public class RoseTree<T>
{
public T Value;
public IEnumerable<Lazy<RoseTree<T>> Children;
public IEnumerable<T> Flatten()
{
yield return Value;
foreach (var childValue in Children.SelectMany(t => t.Value.Flatten()))
yield return childValue;
}
}
我一直在努力想出一个等价的非递归等价物。特别是,尽管很容易得到严格的非递归、拟等价函数,例如:
public IEnumerable<T> FlattenIteratively()
{
var roseTreeQueue = new Stack<RoseTree<T>>();
var values = new Queue<T>();
roseTreeQueue.Push(this);
while (roseTreeQueue.Any())
{
var top = roseTreeQueue.Pop();
values.Enqueue(top.Value);
foreach (var child in top.Children.Reverse())
roseTreeQueue.Push(child.Value);
}
return values;
}
虽然对于具有定义值的有限树,这会产生与Flatten
相同的结果,但对于无限树或具有未定义值的树,这将失败。有没有人看到一种写非递归方法的方法来遍历这个结构,它具有与递归方法相同的特性。
注意:考虑到C#对yield return
函数的重写,调用第一个方法recursive
有点误导。如果有人有更精确的术语,我很乐意拥有。
一个通用的惰性迭代树遍历函数,取自How to flatten tree via LINQ?
public static class TreeHelper
{
public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
{
var stack = new Stack<IEnumerator<T>>();
var e = source.GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
yield return item;
var elements = elementSelector(item);
if (elements == null) continue;
stack.Push(e);
e = elements.GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
在您的情况下,它可以按以下使用
public class RoseTree<T>
{
public T Value;
public IEnumerable<Lazy<RoseTree<T>>> Children;
public IEnumerable<T> Flatten()
{
return Enumerable.Repeat(this, 1)
.Expand(item => item.Children != null ? item.Children.Select(c => c.Value) : null)
.Select(item => item.Value);
}
}
我们可以通过将FlattenIterative
方法显式转换为IEnumerator<T>
来解决此问题。我们定义:
public class RoseTreeEnumerator<T> : IEnumerator<T>, IEnumerable<T>
{
public RoseTree<T> OriginalTree { get; private set; }
private Stack<Lazy<RoseTree<T>>> TreeQueue { get; set; }
private RoseTree<T> CurrentRoseTree { get; set; }
public RoseTreeEnumerator(RoseTree<T> tree)
{
OriginalTree = tree;
TreeQueue = new Stack<Lazy<RoseTree<T>>>();
TreeQueue.Push(new Lazy<RoseTree<T>>(() => tree));
CurrentRoseTree = null;
}
#region IEnumerator<T> Members
public T Current
{
get { return CurrentRoseTree.Value; }
}
public void Dispose()
{
}
#endregion
#region IEnumerator Members
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
if (TreeQueue.Any())
{
CurrentRoseTree = TreeQueue.Pop().Value;
foreach (var tree in CurrentRoseTree.Children.Reverse())
{
TreeQueue.Push(tree);
}
return true;
}
else
{
return false;
}
}
public void Reset()
{
TreeQueue.Clear();
CurrentRoseTree = null;
TreeQueue.Push(new Lazy<RoseTree<T>>(() => OriginalTree));
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return this;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this;
}
#endregion
}
然后可以定义
public IEnumerable<T> FlattenPrime()
{
return new RoseTreeEnumerator<T>(this);
}