Java 返回树的有序字符串
按照此线程中的建议,使用StringBuilder已解决编辑此问题。谢谢:D 你好, 我有一棵树,正试图按顺序返回一个内容字符串 我现在可以用如下方式打印出树: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(); } 但是我想做的是
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?