我试图移植this Genetic Algorithm, 我做了一个递归函数,从一代传到另一代。
但是,由于我在C#(以及一般情况下)的递归新手,当有太多代(超过4500)时,我显然遇到了StackOverflowException。
为了解决这个问题,我让Generation()返回一个bool,所以当遗传算法达到最大适应度(目标)时,它返回true。否则它返回Generation()。
如果它即将溢出(生成> 4500),则返回false。
现在在Main()中,为了保持Generation()运行直到它返回true,我使用while循环,所以它将从递归开始直到它完成。
这比执行Task.Run更有效,所以我采用了这种方法。
这是好习惯吗?是否有更优雅的方法可以在不牺牲性能的情况下阻止StackOverflow?
Population.cs:
class Population
{
public int GenerationNumber { get; private set; }
public int TotalGenerationNumber { get; private set; }
public const int StackGenerationLimit = 4500;
public Population()
{
GenerationNumber = 0;
TotalGenerationNumber = 0;
}
public bool Generation()
{
// Work
// if(HasReachedGoal) return true;
GenerationNumber++;
if(GenerationNumber > StackGenerationLimit)
{
return false;
} else
{
return Generation();
}
}
public void ResetStack()
{
TotalGenerationNumber += GenerationNumber; // I store the total number of generation for information purposes
GenerationNumber = 0; // Reset the recursion depth value
}
}
Program.cs的
class Program
{
static void Main(string[] args)
{
Population population = new Population();
while (!population.Generation()) // Until it reaches its goal
{
population.ResetStack();
}
Console.WriteLine("End. Generations: " + population.TotalGenerationNumber);
}
}
答案 0 :(得分:1)
避免堆栈溢出的最佳方法是不使用递归。您的解决方法已经在答案的一半了。现在你只需要问问自己从递归中获得什么的问题了?如果return Generation();
函数中的Generation
语句改为return false;
,那么您将返回主循环,再次调用Generation()
。
当然,做了这个改变之后,你可以做很多其他整洁的事情。您不再需要重置堆栈,不再需要if语句来检查生成限制,并且所有重复都是从while循环完成的。
所以你的两种方法:
public bool Generation()
{
TotalGenerationNumber++;
// Work
return HasReachedGoal;
}
static void Main(string[] args)
{
Population population = new Population();
bool hasCompleted = false;
while (!hasCompleted) // Until it reaches its goal
{
hasCompleted = population.Generation();
}
Console.WriteLine("End. Generations: " + population.TotalGenerationNumber);
}
请注意,在tidyup中,我引入了一个名为hasCompleted
的bool变量,因为我发现在while条件中使用变量更具可读性,并且更喜欢在循环内部进行工作。
答案 1 :(得分:0)
我认为在这种情况下,最好先准备好while循环并将要检查的数据发送到.Generation调用中。然后,如果它返回false,则更新数据。像这样:
Population population = new Population();
var input = new InputDto() { ... };
while (!population.Generation(input)) // Until it reaches its goal
{
// update input
}
这可以防止过于嵌套的调用导致您描述的错误。