在我的代码中,我无法弄清楚为什么我不断收到“由于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方法无效吗?
答案 0 :(得分:1)
当前的问题是List<string>
是reference type,因此当您将childrenNodes
传递给getShortestPath
(getShortestPath(childrenNodes)
)时,实际上传递对内存中相同列表的引用。
接下来要做的是调用childrenNodes.Clear()
,该列表将为空。因为nodesToCheck
和childrenNodes
都指向同一列表,所以调用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();