EDIT This has been resolved by using StringBuilder as suggested in this thread. Thank you :D
Hello,
I have a tree and am trying to return a String of the content in order.
I can currently print out the tree with something like this:
public void inOrder() {
if (left != null) left.inOrder();
System.out.print(content + " ");
if (right != null) right.inOrder();
}
But what I want to do is return the String (rather than print out each nodes content while recursing) and I can't work out how to do it. I tried many variations of the code below, but it just returns the last element it finds in the recursion.
public String inOrder(String string) {
if (left != null) left.inOrder(string);
string += content;
if (right != null) right.inOrder(string);
return string;
}
Strings are immutable in java. You are not concatenating new String to old one, you are creating new String and make
string
variable point to it. Result is that you have many unrelated Strings andstring
variable points to them in various points in time.You need to pass mutable object to your function such as
StringBuilder
. This solution have additional advantage that it's much more efficient because you are avoiding unnecessary Object allocations.If you want to do this with String concatenation, your second example nearly works - the problem is only that you are throwing away the results of the recursive calls.
But this is (for larger trees) horrible inefficient, since each
+=
in fact creates a new String, copying the characters ofstring
andcontent
- thus each content string is in fact copiedthe number of later nodes
(in inorder sequence) times (+1). A slightly better way would be this:or a bit shorter:
Now each content string is only copied the number of nodes above it times (+1), which for a "usual" (not extremely unbalanced) tree is much smaller. (This variant could easily be parallelized, too.)
But in fact, the StringBuilder version is normally the preferred one, since it copies each content string only one time (when appending it to the StringBuilder), and maybe some more times during internal resizes of the StringBuilder (so if you can estimate the final size before the actual conversion, create a StringBuilder big enough).
Java is pass by value. A reference to an object passed to a method can't be changed by this method. You can change the content of an object, but you can't do that with Strings, because they are immutable (their content can't change).
The line
affects a new String object to the string variable. It doesn't change the content of the original String object.
You need to pass a StringBuilder instance to your method, and append to this StringBuilder:
Strings are immutable in Java and when you add something to a String, a new object is created. Thus, the change is not visible outside the scope of the method.
Try a StringBuilder instead of String:
You could read here: http://www.javaworld.com/javaqa/2000-05/03-qa-0526-pass.html to understand the way Java passes arguments to methods and why Strings immutability is an issue in your original code.
Regards, Sorin.