class Program
{
static void Main(string[] args)
{
Test(0);
}
static void Test(int i)
{
if (i > 30000)
{
return;
}
Test(i + 1);
}
}
为什么在调用上面的示例时获取递归函数并抛出StackOverflowException。
(因为超过默认的递归堆栈大小?)
但我想知道如何解决这个问题。
感谢。
答案 0 :(得分:5)
问题是你做了太多的递归。无论你在做什么,都会使用如此多的递归级别,应该使用循环来解决。
与递归一起工作的算法不会对每个项使用一级递归。通常,您会将每个级别的工作分成两半,因此30000项只需要15级递归。
答案 1 :(得分:5)
你得到一个例外,因为30,000个堆栈帧是一个相当大的数字: - )
您通过以更谨慎的方式使用递归来解决它。递归地解决的理想问题是那些迅速减少“搜索空间”(a)的问题。
例如,二进制树遍历每次重复时搜索空间减半:
def find (searchkey, node):
if node = NULL:
return NULL
if searchkey = node.key:
return node
if searchkey < node.key:
return find (searchkey, node.left)
return find (searchkey, node.right)
添加两个无符号整数(以及上面你自己的算法)不非常适合递归,因为在计算结果之前很久就会耗尽堆栈分配。:
def add (a, b):
if a = 0:
return b
return add (a-1, b+1)
(a)搜索空间可以定义为整套可能的答案。你想尽快减少它。
而且,顺便说一句,递归的理想问题与理论/数学意义上的堆栈空间无关,它们只是可以表达为的任何问题:
(在这个意义上,“简单”意味着接近终止条件。)
理论/数学方法不需要考虑堆栈空间,但我们作为计算机科学家必须这样做。现实设定限制: - )
另请参阅When would I not use recursion?和Situations where you would convert recursion to iteration。
答案 2 :(得分:2)
您收到StackOverflowException
,因为您的堆栈在对Test
的30k次调用中溢出。没有办法“解决”问题,堆栈大小有限(并且也很小)。您可以重新设计代码以便以迭代方式工作。
for( int i = 0; i <= 30000; ++i )
{
Test( i );
}
但是,我认为您的实际用例比这更复杂;否则递归没有收获。
答案 3 :(得分:2)
虽然你可以手动指定新线程的堆栈大小,但我会使用Stack<T>
或循环(这就是你的简化示例所需要的所有内容)所以你不要根本不需要递归,即:
Stack<int> stack = new Stack<int>();
stack.Push(1);
while(stack.Count > 0)
{
int someValue = stack.Pop();
//some calculation based on someValue
if(someValue < 30000)
stack.Push(someValue +1);
}
答案 4 :(得分:1)
看看这个问题:Way to go from recursion to iteration
如果您的递归将达到30k +级别深度......您可能希望将其转换为迭代算法。该问题的答案应该有所帮助。