Java 返回树的有序字符串

Java 返回树的有序字符串,java,recursion,tree,inorder,Java,Recursion,Tree,Inorder,按照此线程中的建议,使用StringBuilder已解决编辑此问题。谢谢:D 你好, 我有一棵树,正试图按顺序返回一个内容字符串 我现在可以用如下方式打印出树: public void inOrder() { if (left != null) left.inOrder(); System.out.print(content + " "); if (right != null) right.inOrder(); } 但是我想做的是

按照此线程中的建议,使用StringBuilder已解决编辑此问题。谢谢:D

你好,

我有一棵树,正试图按顺序返回一个内容字符串

我现在可以用如下方式打印出树:

    public void inOrder() {
        if (left != null) left.inOrder();
        System.out.print(content + " ");
        if (right != null) right.inOrder();
    }
但是我想做的是返回字符串(而不是在递归时打印出每个节点的内容),而我不知道如何做。我尝试了下面代码的许多变体,但它只返回在递归中找到的最后一个元素

 public String inOrder(String string) {
        if (left != null) left.inOrder(string);
        string += content;
        if (right != null) right.inOrder(string);

        return string;
    }

字符串在java中是不可变的。您不是将新字符串连接到旧字符串,而是创建新字符串并使
String
变量指向它。结果是,您有许多不相关的字符串和
string
变量在不同的时间点指向它们


您需要将可变对象传递给函数,例如
StringBuilder
。此解决方案还有另外一个优点,即它的效率更高,因为您可以避免不必要的对象分配。

Java是按值传递的。此方法无法更改传递给方法的对象引用。可以更改对象的内容,但不能使用字符串,因为字符串是不可变的(其内容不能更改)

线路

string += content;
将新字符串对象影响到字符串变量。它不会更改原始字符串对象的内容

您需要将StringBuilder实例传递给您的方法,并附加到此StringBuilder:

public String inOrder() {
    StringBuilder strinBuilder = new StringBuilder();
    postOrder(stringBuilder);
    return stringBuilder.toString();
}

private void postOrder(StringBuilder stringBuilder) {
    if (left != null) left.postOrder(stringBuilder);
    if (right != null) right.postOrder(stringBuilder);
}

字符串在Java中是不可变的,当您向字符串添加内容时,将创建一个新对象。因此,在方法的范围之外,更改是不可见的

尝试使用StringBuilder而不是字符串:

public StringBuilder inOrder(StringBuilder string) {
        if (left != null) left.inOrder(string);
        string.append(content);
        if (right != null) right.inOrder(string);

        return string;
}
您可以在这里阅读:了解Java将参数传递给方法的方式,以及为什么字符串不变性在您的原始代码中是一个问题

问候,,
Sorin.

如果您想通过字符串连接实现这一点,那么第二个示例几乎可以实现—问题只是您正在丢弃递归调用的结果

/**
 * creates an Inorder-string-view of this tree and appends it to the given string.
 * @return the new String.
 */
public String inOrder(String string) {
    if (left != null)
        string = left.inOrder(string);
    string += content;
    if (right != null)
        string = right.inOrder(string);
    return string;
}
但这(对于较大的树)效率极低,因为每个
+=
实际上创建了一个新字符串,复制
字符串
内容
-因此每个内容字符串实际上是复制
后面节点的数量(按顺序)的次数(+1)。更好的方法是:

public String inOrder() {
    String leftS; String rightS;
    if (left != null)
       leftS = left.inOrder();
    else
       leftS = "";
    if (right != null)
       rightS = right.inOrder();
    else
       rightS = "";
    return leftS + content + rightS;
}
或者再短一点:

public String inOrder {
   return
      (left != null ? left.inOrder() : "") +
      content +
      (right != null ? right.inOrder() : "");
}
现在,每个内容字符串只复制它上面的节点数乘以(+1),这对于“普通”(不是非常不平衡)树来说要小得多。(这种变体也可以很容易地并行化。)


但事实上,StringBuilder版本通常是首选版本,因为它只复制每个内容字符串一次(将其附加到StringBuilder时),并且在StringBuilder内部调整大小期间可能会复制更多次(因此,如果您可以在实际转换之前估计最终大小,请创建足够大的StringBuilder).

第二个应该可以用。将left.postOrder更改为left.inOrder.Wow这很有效。非常感谢你。我永远也想不到这一点!除了
String
StringBuilder
的易变性之外,这也是O(n²)算法和(armortized)O(n)算法之间的区别。为什么要按顺序使用postorder?