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(

我在C#中实现了Polygene的java代码()

我的C#代码:

但是我得到了错误的结果:

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 + ")");
    }
}