如何在我的代码中防止StackOverflowException

时间:2019-07-09 00:33:57

标签: c# recursion

在我的代码中,我无法弄清楚为什么我不断收到“由于StackOverflowException而导致进程正在终止”。仅在第二个输出上。

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;

namespace _2018JuniorQ5
{
    class Program
    {
        //Variable Decleration
        public static int pages = 0;
        public static string[] bookFormat;
        public static List<string> alreadyChecked = new List<string>();
        public static List<string> nodesToCheck = new List<string>();
        public static int level = 0;
        public static List<string> childrenNodes = new List<string>();
        public static void Main(string[] args)
        {
            //Get input
            pages = Convert.ToInt32(Console.ReadLine());
            bookFormat = new string[pages];
            for (int x=0; x<pages; x++)
            {
                bookFormat[x] = Console.ReadLine();
            }        
            //Display if all pages are reachable
            Console.WriteLine(getReachablePages(1));
            //Find shortest path
            List<string> NodeBegin = new List<string>();
            NodeBegin.Add("1");
            Console.WriteLine(getShortestPath(NodeBegin));            
        }
        public static string getReachablePages(int pageToCheck)
        {
            string[] options=(bookFormat[pageToCheck - 1]).Split(' ');
            alreadyChecked.Add(Convert.ToString(pageToCheck));
            for (int a=1; a<=Convert.ToInt32(options[0]); a++)
            {
                if (!alreadyChecked.Contains(options[a]))
                {
                    getReachablePages(Convert.ToInt32(options[a]));
                }       
            }
            if (alreadyChecked.Count == pages)
            {
                return "Y";               
            }
            else
            {
                return "N";
            }
            alreadyChecked.Clear();  
        }
        public static int getShortestPath(List<string> nodesToCheck)
        {
            level++;
            childrenNodes.Clear();
            for (int q = 0; q < nodesToCheck.Count; q++)
            {
                string[] options = bookFormat[Convert.ToInt32(nodesToCheck[q])-1].Split(' ');                
                if (options[0] == "0")
                {
                    return level;
                }
                else
                {
                    for (int t = 1; t < options.Length; t++)
                    {
                        if (!alreadyChecked.Contains(options[t]))
                        {
                            childrenNodes.Add(options[t]);
                            alreadyChecked.Add(nodesToCheck[q]);
                        }
                    }
                }
                nodesToCheck.Clear();
            }
            return getShortestPath(childrenNodes);
        }
    }
}

getReachablePages方法的第一个输出有效,并且没有给出任何错误。但是,getShortestPath的第二个输出给出“由于StackOverflowException而导致进程正在终止”错误。有人可以解释为什么getReachablePages方法有效,但是getShortestPath方法无效吗?

1 个答案:

答案 0 :(得分:1)

当前的问题是List<string>reference type,因此当您将childrenNodes传递给getShortestPathgetShortestPath(childrenNodes))时,实际上传递对内存中相同列表的引用。

接下来要做的是调用childrenNodes.Clear(),该列表将为空。因为nodesToCheckchildrenNodes都指向同一列表,所以调用childrenNodes.Clear()意味着您没有要检查的节点。

为什么这会导致StackOverflowException?这是因为nodesToCheck为空时没有退出条件。您只是不断重复调用相同的方法。

我提出以下解决方案:

public static int getShortestPath(List<string> nodesToCheck)
{
    if (!nodesToCheck.Any())
    {
        return -1;
    }

    var childrenNodes = new List<string>();
    level++;
    for (int q = 0; q < nodesToCheck.Count; q++)
    {
        string[] options = bookFormat[Convert.ToInt32(nodesToCheck[q])-1].Split(' ');                
        if (options[0] == "0")
        {
            return level;
        }
        else
        {
            for (int t = 1; t < options.Length; t++)
            {
                if (!alreadyChecked.Contains(options[t]))
                {
                    childrenNodes.Add(options[t]);
                    alreadyChecked.Add(nodesToCheck[q]);
                }
            }
        }
        nodesToCheck.Clear();
    }
    return getShortestPath(childrenNodes);
}
  • nodesToCheck为空时,返回-1(即无路径)。
  • List<string>方法中为childrenNodes创建一个新的getShortestPath

虽然这可以解决您的问题,但我建议您将整个方法设置为独立的。它本质上是一种无状态方法,但是您要在方法外部维护状态,这会导致您看到的问题,如果在多线程环境中调用此方法,可能会导致更多问题。

我注意到的另一个奇怪的事情是,您正在遍历nodesToCheck,但是编写代码的方式意味着您将只考虑第一个节点,因为在该位置清除了nodesToCheck第一次迭代结束时,列表为空。此外,您将nodesToCheck[q]中每个项目的alreadChecked添加到options中一次,我确定这是不对的。

我建议学习在Visual Studio中使用the debugger。调试器使您可以逐行逐步检查代码,检查变量等。这将帮助您在代码中查找问题。

P.S。虽然这不是解决问题的正确方法,但是如果您希望复制列表,则可以使用LINQ's ToList()方法:var listB = listA.ToList();