c# - 您如何将其转换为迭代函数而不是使用嵌套循环进行递归?
问题描述
以下函数导致数百个级别的递归。我想知道是否有人对如何将其切换为循环功能提出建议。我相信在这种情况下执行顺序确实很重要,但我可能需要做更多的调查。我希望我可以直接将它转换为迭代函数而不是递归。
正如您所希望看到的,传递给每个递归级别的唯一参数是“after”。所以递归函数调用本身相对简单,但是围绕调用的循环让我很反感。
我考虑过排队,但“改变”的条件似乎意味着深度优先检查。在将其添加到队列之前,我必须执行部分移位操作,但在当前代码中,下一级递归将立即开始,所以我不能只建立一个项目队列来处理和执行他们按顺序。
我考虑过一个堆栈,但我不确定如何实现它来替换递归。
我决定简化代码,因为它可能有点令人困惑。这是一个骨架(如果您初始化变量,您实际上可以运行它!)这可能更像是“伪”
private void DataChangedRecursive(LinkedNode node)
{
InitializeVariables();
try
{
foreach (LinkedNode after in node.After)
{
var afterDetails = after.Before;
bool changed = CheckData(afterDetails);
if (changed)
{
DataChangedRecursive(afterDetails);
}
}
}
catch
{
// Assume relavant error handling at this level in the stack. This probably isn't important to maintain, but it'd be interested if we could.
throw;
}
}
public object InitializeVariables()
{
// Assume relavant work happens here.
return new object();
}
public bool CheckData(LinkedNode dr)
{
// Logic is that something changes, so it needs to save. This does a bunch of comparisons on the current item.
return dr.DataChanged;
}
public class LinkedNode
{
public LinkedNode Before {get;set;}
public bool DataChanged {get;set;}
public List<LinkedNode> After {get;set;}
}
解决方案
终于想通了,顿悟了。事实证明,处理递归和循环的最简单方法是利用 IEnumerator。它要求您手动处理迭代(没有 for 循环),但递归和循环的顺序将是相同的。
我将函数分为两部分,入口函数和与“递归”一起进行迭代的函数。从本质上讲,这将保证所有子节点首先完全完成,就像递归一样,并返回父节点中正确的迭代点。理论上,这应该适用于任何内部带有循环的递归函数。
private void DataChangedRecursive(LinkedNode node)
{
try
{
DataChanged(node);
}
catch
{
throw;
}
}
private void DataChanged(LinkedNode node)
{
var state = new Stack<IEnumerator<LinkedNode>>();
state.Push(node.After.GetEnumerator());
while (state.Count > 0)
{
InitializeVariables();
while (state.Peek().MoveNext())
{
ItemWithPredPostcessor after = state.Peek().Current;
ItemWithPredPostcessor afterDetails = after.Before;
bool dataChanged = StartShift(afterDetails);
if (dataChanged)
{
Save(afterDetails);
state.Push(afterDetails.After.GetEnumerator());
}
}
state.Pop(); // Remove current from list, as we've completed.
}
}
推荐阅读
- javascript - BodyBuilder.js 查询任何数组
- selenium - 如何处理 selenium 中的文件资源管理器对话框
- php - Codeigniter 使用输入数组键为每个字段上传多个文件
- javascript - Javascript toLocaleString 忽略时区和语言环境
- angular - 在 pipe() 链中合并两个 observables
- javascript - 使用 HTML 和 Javascript 编写多运算计算器
- ios - 如何在没有 iOS 的情况下使用 Xcode 测试我的应用程序
- python-3.x - MacOs Catalina AWS CLI 错误“ImportError: cannot import name 'ssl' from 'urllib3.util.ssl_'”
- android - android/flutter 中的 settings_aar.gradle 有什么用?
- admob - AdMob 激励视频广告显示展示次数,但没有收入,这是什么?