递归函数中的变量保持其值
本文关键字:变量 递归函数 | 更新日期: 2023-09-27 18:34:05
我正在尝试将此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;
}
}
}
这应该可以解决异常:
newpath.AddRange()
在返回null 时引发异常find_path()
。
将find_path()
结果分配给变量,并在添加到变量之前检查 null 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/