эквивалент передачи по ссылке в Java для нулевых переданных указателей

У меня есть вопрос о том, как лучше всего передать объект, который может содержать null, другим методам. Другой метод создаст новый экземпляр, если объект, если переданный объект имеет значение null. Мой вопрос заключается в том, как разрешить второму методу изменять исходный начальный переданный нулевой указатель объекта. По сути, я столкнулся с этой проблемой при чтении BST из файла и создании дерева. Я думаю, что объяснение проблемы на том же примере имеет больше смысла:

В приведенном ниже коде я читаю и создаю BST из всех значений, хранящихся в очереди. Значения Queue — это обход дерева по порядку, который я прочитал из другого метода.

    TreeNode root2;
public void readBST(Queue<Integer> input){
    if (input==null || input.isEmpty()) return;     
    int i=input.poll();
    root2 = new TreeNode(i);
    readBSTHelper(root2.leftChild , input, Integer.MIN_VALUE , i-1);
    readBSTHelper(root2.rightChild, input, i+1, Integer.MAX_VALUE);
}

private void readBSTHelper(TreeNode curr, Queue<Integer> input, int min, int max){
    if (input==null && input.isEmpty()) return;
    int i = input.peek();
    if (i>=min && i<=max){
        input.poll();
        curr = new TreeNode(i);
        readBSTHelper(curr.leftChild, input, min, i-1);
        readBSTHelper(curr.rightChild,input, i+1, max);
    }
}

Однако проблема, с которой я сталкиваюсь, заключается в том, что когда создается root2, leftChild и rightChild становятся null. на самом деле TreeNode(i) составляет TreeNode с data=i и leftChild и rightChild равными null. Когда я вызываю readBSTHelper, передавая root2.leftChild, он передает указатель null. Поскольку это указатель null, копия указателя null передается в readBSTHelper. Таким образом, результат из readBSTHelper теряется и никогда не возвращается/присваивается реальному root2.leftChild. Мы можем предотвратить такую ​​проблему в C++, передав ссылку исходного указателя. Мне удалось временно решить проблему, изменив код, как показано ниже:

    TreeNode root2;
public void readBST(Queue<Integer> input){
    if (input==null || input.isEmpty()) return;     
    int i=input.poll();
    root2 = new TreeNode(i);
    readBSTHelper(root2, "left", input, Integer.MIN_VALUE , i-1);
    readBSTHelper(root2, "right", input, i+1, Integer.MAX_VALUE);
}
private void readBSTHelper(TreeNode curr, String side, Queue<Integer> input, int min, int max){
    if (input.isEmpty()) return;
    int i = input.peek();
    if (i>=min && i<=max){
        input.poll();
        if (side.equals("left")) {
            curr.leftChild = new TreeNode(i);
            readBSTHelper(curr.leftChild,"left", input, min, i-1);
            readBSTHelper(curr.leftChild, "right", input, i+1, max);
        } else {
            curr.rightChild = new TreeNode(i);
            readBSTHelper(curr.rightChild,"left", input, min, i-1);
            readBSTHelper(curr.rightChild, "right", input, i+1, max);
        }

    }
}

Но этот код выглядит уродливым для меня. Любые советы о том, как заставить работать первый код?


person reza    schedule 08.03.2013    source источник
comment
Вы не можете передать по ссылке в Java (ну, технически вы можете, но это долгий и утомительный процесс с отражением).   -  person Benjamin Gruenbaum    schedule 08.03.2013
comment
Возможный ответ: stackoverflow.com/questions/ 15203969/   -  person Dariusz    schedule 08.03.2013
comment
@Benjamin Я знаю, что в java нельзя пройти по ссылке. Мой вопрос был о том, как мы можем достичь эквивалентной функциональности в приведенном выше коде.   -  person reza    schedule 08.03.2013
comment
возможный дубликат Передача по ссылке в Java?   -  person jachguate    schedule 08.03.2013
comment
@Dariusz Я проверил ваше предложение, но это всего лишь класс-оболочка. Я не понимаю, как оболочка может решить вышеуказанную проблему. мы по-прежнему вызываем вспомогательный метод с нулевым объектом, что приводит к той же проблеме.   -  person reza    schedule 08.03.2013
comment
@reza Инициализировать узлы, если они нулевые во внешней функции, а затем выполнять всю логику в самой функции.   -  person Benjamin Gruenbaum    schedule 08.03.2013
comment
@jachguate Это не имеет НИЧЕГО общего с передачей по ссылке. Я упоминал об этом сбоку. Вопрос в том, как я могу решить проблему копирования нулевого указателя в подметодах   -  person reza    schedule 08.03.2013
comment
@reza Похоже, у вас есть проблема, которую вы не можете решить с помощью java с вашим текущим подходом, и ИМХО предложенный дубликат четко отвечает на ваш вопрос.   -  person jachguate    schedule 08.03.2013


Ответы (1)


Вариант 1. Оболочка

class NodeWrapper
{
  TreeNode node;
}

class TreeNode
{
  ...
  TreeNode(int num)
  {
    leftChild = new NodeWrapper();
    rightChild = new NodeWrapper();
    ...
  }
  NodeWrapper leftChild, rightChild;
}

void readBSTHelper(NodeWrapper curr, Queue<Integer> input, int min, int max)
{
  ...
}

Вариант 2. Инициализировать дочерние элементы в конструкторе

Я предлагаю иметь отдельный конструктор, предназначенный для этой цели (не такой, как показано ниже), иначе ваша функция вставки создаст дочерние элементы по ошибке.

class TreeNode
{
  ...
  TreeNode()
  {
    val = null;
  }
  TreeNode(int num)
  {
    init(num);
  }
  init(int num)
  {
    leftChild = new TreeNode();
    rightChild = new TreeNode();
    val == num;
  }
  Integer val;
}

public void readBST(Queue<Integer> input){
    if (input==null || input.isEmpty()) return;     
    int i=input.poll();
    root2 = new TreeNode(i);
    if (!readBSTHelper(root2.leftChild , input, Integer.MIN_VALUE , i-1))
      root2.leftChild = null; // delete child if not populated
    if (!readBSTHelper(root2.rightChild, input, i+1, Integer.MAX_VALUE))
      root2.rightChild = null; // delete child if not populated
}

boolean readBSTHelper(TreeNode curr, Queue<Integer> input, int min, int max){
    if (input==null && input.isEmpty()) return false;
    int i = input.peek();
    if (i>=min && i<=max){
        input.poll();
        curr.init(i);
        if (!readBSTHelper(curr.leftChild, input, min, i-1))
          curr.leftChild = null;
        if (!readBSTHelper(curr.rightChild, input, i+1, max))
          curr.rightChild = null;
        return true;
    }
    return false;
}
person Bernhard Barker    schedule 08.03.2013
comment
это похоже на использование фиктивного узла (здесь вы назвали его NodeWrapper) для всех нулевых TreeNodes. неплохо, но я пытаюсь понять, могу ли я использовать какой-то другой метод для решения этой проблемы. - person reza; 08.03.2013
comment
@reza На самом деле NodeWrapper предназначен для всех TreeNode, а не только для null. Его цель будет аналогична указателю в C++. Также добавлен еще один вариант, см. редактирование. - person Bernhard Barker; 08.03.2013
comment
спасибо за второе предложение. Но он также хранит так много дополнительных нулевых значений. Он устанавливает все нулевые дочерние элементы равными новому TreeNode с нулевым значением. Интересно, можно ли это предотвратить? - person reza; 08.03.2013
comment
@reza Обратите внимание, что он удаляет их при повторении резервного копирования дерева. Лучшего способа сейчас не придумаешь. - person Bernhard Barker; 08.03.2013