【发布时间】:2021-09-03 20:01:18
【问题描述】:
我正在尝试编写一个递归方法来查找从 m 的左上角到右下角的所有可能方式的数量 n 网格(不向上移动)。
变量 key 应该保存 m 和 n 的当前值,但如果我尝试使用类字段,这个变量表现得像是落后了一步之类的。
以下代码将以未处理的异常结束:
已添加具有相同密钥的项目。键:1,1
看起来很像,比如说,当你的初始 m 和 n 分别是 3 和 2 时,(1, 2) 的函数将尝试添加它的 value 到带有“1,1”键的字典:
class Finder
{
public Finder()
{
memo = new(new List<KeyValuePair<string, ulong>>
{ new KeyValuePair<string, ulong>("1,1", 1) });
}
private Dictionary<string, ulong> memo;
private string key;
private ulong value;
public ulong FindPaths(int m, int n)
{
key = String.Format("{0},{1}", (m < n ? m : n), (m > n ? m : n));
if (memo.ContainsKey(key))
{
return memo[key];
}
if (m == 0 || n == 0)
{
return 0;
}
value = FindPaths(m - 1, n) + FindPaths(m, n - 1);
memo.Add(key, value);
return value;
}
}
当我将 Add 方法中预先计算的 key 更改为最初计算它的相同表达式时,问题就消失了:
memo.Add(String.Format("{0},{1}", (m < n ? m : n), (m > n ? m : n)), value);
现在,如果我们将类字段替换为局部变量,一切都会按预期进行:
class Finder
{
public Finder()
{
memo = new(new List<KeyValuePair<string, ulong>>
{ new KeyValuePair<string, ulong>("1,1", 1) });
}
private Dictionary<string, ulong> memo;
private ulong value;
public ulong FindPaths(int m, int n)
{
string key;
key = String.Format("{0},{1}", (m < n ? m : n), (m > n ? m : n));
if (memo.ContainsKey(key))
{
return memo[key];
}
if (m == 0 || n == 0)
{
return 0;
}
value = FindPaths(m - 1, n) + FindPaths(m, n - 1);
memo.Add(key, value);
return value;
}
}
这种行为差异是否是由于类字段位于堆上而局部变量位于堆栈上这一事实引起的?我认为在递归方法中使用类字段比每次方法调用自身时创建本地更实用。
请帮助我更深入地了解这个主题。
【问题讨论】:
-
使用字段递归会更改 key 的值,从而破坏 memo.Add(key, value) 调用。请务必尽早使用 small 案例进行测试,以便在使用调试器单步执行时发现此问题。
标签: c# .net heap-memory stack-memory