【问题标题】:Recursive Function -trying to understand递归函数 - 试图理解
【发布时间】:2015-03-23 17:12:28
【问题描述】:

我对这段代码有疑问。这不是工作或家庭作业。我只是想了解递归函数。代码一开始是可以运行的,但是当它发现一个超过 22000 个字符的单词时,它导致了一个错误的抛出 - 一个 stackoverflowexception。

这是代码

using System;

namespace Palindrome
{
    using System.IO;

    public class Program
    {
        public static void Main()
        {
            int c = 0;

            string[] l = File.ReadAllLines("UKACD17.TXT");
            for (int i = 0; i < l.Length; i++)
            {
                string ll = l[i];
                if (T(ll))
                {
                    Console.WriteLine(ll);
                    c++;
                }
            }

            Console.WriteLine("Found {0} palindromes.", c);
            Console.ReadLine();
        }

        private static bool T(string s)
        {
            if (string.IsNullOrWhiteSpace(s)) return false;
            return s.Length == 1 || (s[0] == s[s.Length - 1] && T(s.Substring(1, s.Length - 2)));
        }
    }}

【问题讨论】:

  • 栈的大小是有限的。
  • 您可以简单地制定出更高效的递归和非递归解决方案,但我想这不是问题所在 - 效率。

标签: c# function recursion


【解决方案1】:

该方法在逻辑上看起来是正确的,但由于执行代码的计算机的实际限制,它不起作用。

每当您调用一个方法时,它都会将调用方法的状态推送到堆栈上 - 基本上是一块包含数据的内存块,一旦被调用的方法执行完毕,这些数据将允许在调用方法中继续执行。

这个内存块大小不一,因此如果您尝试递归调用该方法 11000 次(对于 22000 字符的初始输入),则需要推送 11000 个堆栈帧 - 这显然是一种方法比允许的更深的递归(它也可能在 11000 之前很久就放弃了)。

我想,这个限制已经设置好了,否则你会用完有限的内存,而这些内存可以用于其他更有用的事情。

你可以把它变成一个循环,而不是递归调用该方法:

private static boolean T(string s) {
  if (string.IsNullOrWhiteSpace(s)) return false;
  int i = 0;
  int j = s.length - 1;
  while (i < j) {
    if (s[i] != s[j]) return false;
    i++; j--;
  }
  return true;
}

这使用了两个指向彼此移动的字符串的指针——在每一步,如果它们指向不同的字符,它就不能是回文,所以你可以返回 false;否则,将它们彼此靠近并重复。

调用成本要低得多,因为不需要推送堆栈帧 - 您所做的只是比较字符并增加/减少几个整数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    相关资源
    最近更新 更多