3

EDITこれは、このスレッドで提案されているように 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;
    }
4

4 に答える 4

5

文字列はJavaでは不変です。新しい文字列を古い文字列に連結するのではなく、新しい文字列を作成してstring変数がそれを指すようにします。その結果、さまざまな時点で、多くの無関係な文字列とstringそれらへの可変ポイントがあります。

などの関数に可変オブジェクトを渡す必要がありますStringBuilder。このソリューションには、不要なオブジェクトの割り当てを回避できるため、はるかに効率的であるという追加の利点があります。

于 2011-02-22T11:06:16.873 に答える
3

これを String 連結で行いたい場合、2 番目の例はほぼ機能します。問題は、再帰呼び出しの結果を破棄していることだけです。

/**
 * 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;
}

しかし、これは (より大きなツリーの場合) 非常に非効率的です。それぞれ+=が実際に新しい String を作成し、stringandの文字をコピーするためcontent、実際には各コンテンツ文字列がthe number of later nodes(順序どおりに) 回 (+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 に追加するときに) 1 回だけコピーし、StringBuilder の内部サイズ変更中にさらに数回コピーするためです (したがって、最終的なサイズを見積もることができる場合)。実際の変換の前に十分な大きさの StringBuilder を作成します)。

于 2011-02-22T14:10:33.050 に答える
2

文字列はJavaでは不変であり、文字列に何かを追加すると、新しいオブジェクトが作成されます。したがって、変更はメソッドの範囲外には表示されません。

Stringの代わりにStringBuilderを試してください。

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

        return string;
}

http://www.javaworld.com/javaqa/2000-05/03-qa-0526-pass.htmlを読んで、Javaが引数をメソッドに渡す方法と、文字列の不変性が元のコードで問題になる理由を理解してください

よろしく、ソリン。

于 2011-02-22T11:07:36.793 に答える
0

Javaは値渡しです。メソッドに渡されたオブジェクトへの参照は、このメソッドでは変更できません。オブジェクトのコンテンツは変更できますが、文字列は不変であるため(コンテンツは変更できないため)、文字列を使用して変更することはできません。

この線

string += content;

文字列変数への新しいStringオブジェクトに影響します。元のStringオブジェクトの内容は変更されません。

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);
}
于 2011-02-22T11:06:55.780 に答える