Java C“实施——”;打印所有平衡圆括号的组合“;
我在C#中实现了Polygene的java代码() 我的C#代码: 但是我得到了错误的结果:Java C“实施——”;打印所有平衡圆括号的组合“;,java,c#,recursion,Java,C#,Recursion,我在C#中实现了Polygene的java代码() 我的C#代码: 但是我得到了错误的结果: CombiParentheses(3, 0, tempString2); {{{}}} }{}} }{} }{{}} }{} 是什么导致了C#和Java实现之间的这种差异?问题不在于Java->C#翻译,而在于您将字符串翻译成了StringBuilder。当你打电话的时候 str.Append("("); 您正在将“(”附加到当前字符串生成器实例(str)中,并且 CombiParentheses(
CombiParentheses(3, 0, tempString2);
{{{}}}
}{}}
}{}
}{{}}
}{}
是什么导致了C#和Java实现之间的这种差异?问题不在于Java->C#翻译,而在于您将字符串翻译成了StringBuilder。当你打电话的时候
str.Append("(");
您正在将“(”附加到当前字符串生成器实例(str
)中,并且
CombiParentheses(open - 1, close + 1, str.Append("("));
在方法调用中传递该实例本身,而不是新实例
看问题的一个简单方法是:假设你在打电话
CombiParentheses(2, 0, str);
当写入第二个输出字符串时,调用堆栈将被删除
CombiParentheses(2, 0, str):
CombiParentheses(1, 1, str.Append("(")):
CombiParentheses(0, 2, str.Append("(")):
CombiParentheses(0, 1, str.Append(")")):
CombiParentheses(0, 0, str.Append(")")); // StringBuilder was reset here!
CombiParentheses(1, 0, str.Append(")")):
CombiParentheses(0, 1, str.Append("(")):
CombiParentheses(0, 0, str.Append(")"));
因为您使用的是单个字符串生成器实例,并且在调用堆栈进入之前清除了它
CombiParentheses(1, 0, str.Append(")"));
下一个输出将匹配该调用的输出,就好像str上还没有字符一样,而不是您期望的输出(就好像str上还有一个”(
)
如果改为使用字符串,则在执行(字符串+”)时
,结果是一个新的字符串,与您修改的对象不同,因此问题不会出现,当您返回到在递归执行中较早进行的CombiParentheses
调用时,仍然会收到CombiParentheses
调用的原始字符串
您可以使用此选项在运行时查看它:
public static void CombiParentheses(int open, int close, StringBuilder str)
{
Console.WriteLine("open: {0}; close: {1}; str: {2}", open, close, str.ToString());
if (open == 0 && close == 0)
{
Console.WriteLine(str.ToString());
str.Clear();
}
if (open > 0)
{
CombiParentheses(open - 1, close + 1, str.Append("("));
}
if (close > 0)
{
CombiParentheses(open, close - 1, str.Append(")"));
}
}
public static void CombiParenthesesFixed(int open, int close, string str)
{
Console.WriteLine("open: {0}; close: {1}; str: {2}", open, close, str);
if (open == 0 && close == 0)
{
Console.WriteLine(str);
}
if (open > 0)
{
CombiParentheses(open - 1, close + 1, str + "(");
}
if (close > 0)
{
CombiParentheses(open, close - 1, str + ")");
}
}
我的直觉是它与Java版本中
StringBuilder
与string
的使用有关返回原始的StringBuilder
对象本身,而不是新的对象。@MitchWheat:你能解释一下吗?我看不出与Java版本有任何其他区别。也许你在链接文章中看到的是优化版本?问题是Java版本使用字符串。字符串是不可变的。如果你调用递归方法使用字符串,您将创建递归调用中使用的新字符串实例。您使用StringBuilder,每次调用都传递相同的实例。让我们看看您的第一个rec.call:string将s+“{
传递给调用。同一个调用,但第二个rec.call将传递原始的s
+}
。您的StringBuilder将包含前面添加的开口支撑。要明确:第一次调用:open=close>0
s=“”
,与str==”
相同。在第一次调用时,调用您传递的“{
(因为s
为空)。这也与使用StringBuilder相同。但是第二个rec.调用将在字符串版本中通过“}”
,因为s
为空,但在StringBuilder版本中它将通过“{}”
,因为之前的调用中为StringBuilder添加了右括号。
public static void CombiParentheses(int open, int close, StringBuilder str)
{
Console.WriteLine("open: {0}; close: {1}; str: {2}", open, close, str.ToString());
if (open == 0 && close == 0)
{
Console.WriteLine(str.ToString());
str.Clear();
}
if (open > 0)
{
CombiParentheses(open - 1, close + 1, str.Append("("));
}
if (close > 0)
{
CombiParentheses(open, close - 1, str.Append(")"));
}
}
public static void CombiParenthesesFixed(int open, int close, string str)
{
Console.WriteLine("open: {0}; close: {1}; str: {2}", open, close, str);
if (open == 0 && close == 0)
{
Console.WriteLine(str);
}
if (open > 0)
{
CombiParentheses(open - 1, close + 1, str + "(");
}
if (close > 0)
{
CombiParentheses(open, close - 1, str + ")");
}
}