Возврат неупорядоченной строки дерева

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

person guesswork    schedule 22.02.2011    source источник
comment
Второй должен работать. Измените left.postOrder на left.inOrder.   -  person Suraj Chandran    schedule 22.02.2011


Ответы (4)


Строки неизменяемы в java. Вы не объединяете новую строку со старой, вы создаете новую строку и указываете на нее переменную string. В результате у вас есть много несвязанных строк, и переменная string указывает на них в разные моменты времени.

Вам нужно передать изменяемый объект вашей функции, такой как StringBuilder. Это решение имеет дополнительное преимущество, заключающееся в том, что оно намного эффективнее, поскольку вы избегаете ненужного выделения объектов.

person Slartibartfast    schedule 22.02.2011
comment
Вау, это работает. Большое спасибо. Я бы никогда не догадался об этом! - person guesswork; 22.02.2011
comment
Помимо аспекта изменчивости String по сравнению с StringBuilder, это также разница между алгоритмом O (n²) и (усиленным) алгоритмом O (n). - person Fred Foo; 22.02.2011

Если вы хотите сделать это с конкатенацией строк, ваш второй пример почти работает - проблема только в том, что вы отбрасываете результаты рекурсивных вызовов.

/**
 * 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 и 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) и, возможно, еще несколько раз во время внутреннего изменения размеров StringBuilder ( поэтому, если вы можете оценить окончательный размер до фактического преобразования, создайте достаточно большой StringBuilder).

person Paŭlo Ebermann    schedule 22.02.2011

Строки неизменяемы в Java, и когда вы что-то добавляете к строке, создается новый объект. Таким образом, изменение не видно за рамками метода.

Попробуйте StringBuilder вместо String:

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 передает аргументы методам и почему неизменность строк является проблемой в исходном коде.

С уважением, Сорин.

person Sorin    schedule 22.02.2011

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);
}
person JB Nizet    schedule 22.02.2011
comment
Почему вы используете почтовый заказ в заказе? - person Dejell; 13.10.2013