我正在尝试将此PHP代码转换为C#代码。
假设我们有一些数字矩阵
1 2 3
4 5 6
7 8 9
如果我们只能在任何方向上进行一步,而不重复自己,那么这个PHP代码会找到多少组合。 从数字1可以是例如:
1,2
1,2,3
1,2,3,5
1,2,3,6
1,2,3,5,9
......等等。
这个PHP代码工作正常,但是当我在C#中做同样的结果时,我会收到错误。
我发现了变量path
的问题。在递归中,它在深度时存储它的值。
我该如何解决这个问题?我知道有一些静态变量问题,但无法找到。
<?php
$paths = array();
function find_path($graph, $start, $end, $path = array())
{
global $paths;
$path[] = $start;
if ($start == $end)
return $path;
if (!isset($graph[$start]))
return false;
foreach($graph[$start] as $node) {
if (!in_array($node, $path)) {
$newpath = find_path($graph, $node, $end, $path);
if ($newpath)
$paths[] = implode(',', $newpath);
}
}
return array();
}
$graph = array(
'1' => array('2', '4', '5'),
'2' => array('1', '3', '5', '4', '6'),
'3' => array('2', '5', '6'),
'4' => array('1', '2', '7', '8', '5'),
'5' => array('1', '2', '3', '4', '6', '7', '8'),
'6' => array('3', '2', '5', '9', '8'),
'7' => array('4', '5', '8'),
'8' => array('4', '6', '6', '7', '9'),
'9' => array('5', '6', '8')
);
for($i = 1; $i <= 9; $i++)
for($j = 1; $j <= 9; $j++)
find_path($graph, (string) $i, (string) $j);
using System;
using System.Collections.Generic;
namespace ConsoleSlovoMania
{
class Program
{
public static List<string> newpath = new List<string>();
static void Main()
{
int[][] graph = new int[10][];
graph[1] = new int[] { 2, 4, 5 };
graph[2] = new int[] { 1, 3, 5, 4, 6 };
graph[3] = new int[] { 2, 5, 6 };
graph[4] = new int[] { 1, 2, 7, 8, 5 };
graph[5] = new int[] { 1, 2, 3, 4, 6, 7, 8 };
graph[6] = new int[] { 3, 2, 5, 9, 8 };
graph[7] = new int[] { 4, 5, 8};
graph[8] = new int[] { 4, 6, 6, 7, 9};
graph[9] = new int[] { 5, 6, 8 };
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
find_path(graph, i, j);
}
}
Console.ReadKey();
}
private static List<string> find_path(int[][] graph, int start, int end, List<string> path = null)
{
Console.Write("start = " + start + " | end = " + end);
Console.WriteLine();
if (path == null)
{
path = new List<string>();
}
path.Add(start.ToString());
path.ForEach(Console.Write);
Console.WriteLine();
if (start == end)
{
return path;
}
foreach (int node in graph[start])
{
if (path.Exists(element => element == node.ToString()) == false)
{
newpath.AddRange(find_path(graph, node, end, path));
if (newpath.Count > 0)
{
//newpath.ForEach(Console.WriteLine);
newpath.Clear();
}
}
}
return path = null;
}
}
}
答案 0 :(得分:1)
这应该可以修复异常:
当newpath.AddRange()
返回null时, find_path()
抛出异常。
将find_path()
的结果分配给变量并在添加到newpath
要修复逻辑错误,请记住在.NET List<String>
中是一个对象,当您在递归步骤中传递path
时,您将引用的值传递给该对象,而不是对象的副本。轻松修复:只需复制列表(使用LINQ轻松),如下所示:
path.ToList()
这是完整的固定C#代码。我重新安排了它,并将几个变量重命名为PHP代码的1:1音译;它使查找和修复List<String> path
突变问题变得更容易。
namespace ConsoleSlovoMania
{
class Program
{
public static List<string> paths = new List<string>();
private static List<string> find_path(int[][] graph, int start, int end, List<string> path = null)
{
if (path == null)
{
path = new List<string>();
}
path.Add(start.ToString());
if (start == end)
{
return path;
}
foreach (int node in graph[start])
{
if (!path.Contains(node.ToString()))
{
// before calling recursive step, copy path instead of passing around object reference value
List<String> newPath = find_path(graph, node, end, path.ToList());
if (newPath != null)
{
paths.Add(String.Join(",", newPath.ToArray()));
}
}
}
return path = null;
}
static void Main()
{
int[][] graph = new int[10][];
graph[1] = new int[] { 2, 4, 5 };
graph[2] = new int[] { 1, 3, 5, 4, 6 };
graph[3] = new int[] { 2, 5, 6 };
graph[4] = new int[] { 1, 2, 7, 8, 5 };
graph[5] = new int[] { 1, 2, 3, 4, 6, 7, 8 };
graph[6] = new int[] { 3, 2, 5, 9, 8 };
graph[7] = new int[] { 4, 5, 8};
graph[8] = new int[] { 4, 6, 6, 7, 9};
graph[9] = new int[] { 5, 6, 8 };
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
find_path(graph, i, j);
}
}
Console.ReadKey();
}
}
}
要验证结果,可以在Console.ReadyKey()
的行上放置一个断点,并验证paths
的内容是否等同于PHP代码返回的结果。对于PHP,您可以使用调试器,或print_r($paths)
来吐出数组。我通过将paths
和$paths
序列化为JSON来自动化验证,这在jsFiddle中非常容易测试,请参见此处:http://jsfiddle.net/ea89L8x8/