вставка узлов в двоичное дерево в вопросе Java - PullRequest
3 голосов
/ 06 апреля 2011

Я перехожу из C ++ в Java, и я путаю двоичные деревья с Java. единственный способ иметь класс Node - сделать его внутренним статическим классом? все примеры, которые я вижу, делают это. Тем не менее, способ, которым я делаю это, у меня есть класс узла, и класс двоичного дерева использует этот класс узла. но я продолжаю получать ошибку, когда я пытаюсь вставить в дерево после второй вставки. я получаю исключение в этой строке if(dataIn <= nodeIn.getLeft().getData()){

Я запутался в том, что я сделал неправильно ... вот мой код для вставки, который у меня есть. заранее спасибо ..

public void insert(int dataIn){
    root = insert(root, dataIn);
}

private Node insert(Node nodeIn, int dataIn){
    if(nodeIn==null){
        nodeIn = new Node(null, null, dataIn);
    }else{
        if(dataIn <= nodeIn.getLeft().getData()){
            nodeIn.setLeft(insert(nodeIn.getLeft(), dataIn));
        }else{
            nodeIn.setRight(insert(nodeIn.getRight(), dataIn));
        }
    }

    return nodeIn;
}

Ответы [ 8 ]

9 голосов
/ 06 апреля 2011

Частично причина этого в том, что «Узел» не должен быть параметром для метода вставки, вы должны вызывать метод вставки, определенный в узле.

Итак, давайте предположим, что вы держите узел "Root" в своем "нормальном коде" - давайте назовем его "rootNode" просто для неясности.

Хорошо, ваш код для вставки в дерево будет:

rootNode.insert(newValue);

Достаточно просто.

Теперь, чтобы определить этот метод.

public class Node {
    private int value;
    private Node lower;
    private Node higher;

    public void insert(int newValue) {
        if (newValue < value)
            if(lower == null)
                lower=new Node(value);
            else
                lower.insert(newValue);
        else
            if(higher == null)
                higher=new Node(value);
            else
                higher.insert(newValue);
      }

 // and you'll need a constructor
    public Node(int value) {
        this.value=value;
    }
}

Это должно читаться намного яснее. Я собираюсь нажать «Пост», затем я отредактирую его и пойму, как легко преломить этот злой злой код для копирования и вставки.

Если подумать, я оставлю это там, потому что это более читабельно. Лучшее исправление, которое я вижу, это сделать узлы массивом, тогда вы получите:

public class Node {

    private int value;
    private Node[] nodes=new Node[2];
    private final int LOWER=0;
    private final int HIGHER=1;

    public void insert(int newValue) {
        int index=LOWER;
        if (newValue > value)
            index=HIGHER;

        if(nodes[index] == null)
            nodes[index]=new Node(value);
            else
                nodes[index].insert(newValue);
        }
    }

Но я не буду заменять оригинал, потому что, как я уже сказал, он понятнее.

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

С дополнительными соображениями относительно комментария @ ted и OO - getLeft и getRight даже не должны быть проблемой. За абстракцией нет необходимости.

В общем, вам, вероятно, нужны следующие методы в Node:

public boolean doesContain(int value) {
     if(value == this.value)
         return true
     else
         return nodes[ this.value < value ? LOWER : HIGHER].doesContain(value);
}

и, возможно,

public void getValuesSorted(LinkedList l) {
    nodes[LOWER].getValuesSorted(l);
    l.put(value);
    nodes[HIGHER].getValuesSorted(l);
}

Тогда вам даже не нужно показывать, что это дерево, с которым вы имеете дело - лучше абстракция OO.

4 голосов
/ 06 апреля 2011

Вам нужно проверить, является ли nodeIn.getLeft() == null.

1 голос
/ 12 марта 2017

Вы можете использовать приведенный ниже код, чтобы очистить ваше понимание. В основном мы не используем какой-либо другой класс, все можно сделать внутри одного класса Node. Вот очень простой пример, который, я считаю, может быть полезным ... Также, когда я вижу, у вас есть два метода, в которых вы предоставили только данные, а не root. Поверьте мне, лучше иметь root в вашем основном классе. рассуждая, у нас это удобно, когда бы нам ни понадобилось кэшировать.

public Node insert(Node root, Node newNode) {
if (root == null) { 
    root = newNode;
} else {
    if(root.data > newNode.data) {
        root.left = insert(root.left, newNode);
    } else {
        root.right = insert(root.right, newNode);
    }
}
return root;

}

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

Node root = new Node(10);
    root.insert(root, new Node(5));
    root.insert(root, new Node(3));
    root.insert(root, new Node(6));
    root.insert(root, new Node(1));
1 голос
/ 06 апреля 2011

единственный способ иметь класс Node - сделать его внутренним статическим классом? все примеры, которые я вижу, делают это.

номер

Класс Node не должен быть внутренним или вложенным классом. (Строго говоря, «статический внутренний» класс - это вложенный класс.)

Однако, только внутренний или вложенный класс может быть private. Если ваш Node класс является обычным классом, вы предоставляете детали реализации (как минимум) другим классам в том же пакете. Это плохая идея ... и это объясняет, почему вы видите, что класс Node объявлен таким, какой он есть.

0 голосов
/ 26 февраля 2018
public class TreeNode
{
    private int data;
    private TreeNode left;
    private TreeNode right;

    public Tree( )
    {
        data = 0;
        left = null;
        right = null;
    }

    public Tree( int initialInfo, TreeNode initialLeft, TreeNode initialRight )
    {
        data = initialInfo;
        left = initialLeft;
        right = initialRight;
    }

    public void setLeft( TreeNode newLeft )
    {
        left = newLeft;
    }

    public void setRight( TreeNode newRight )
    {
        right = newRight;
    }

    public void insert( int element )
    {
        if( element <= data )
        {
            if( left == null )
                setLeft( new TreeNode( element, null, null ) );
            else
                left.insert( element );
        }
        else
        {
            if( right == null )
                setRight( new TreeNode( element, null, null ) );
            else
                right.insert( element );
        }
    }
}
0 голосов
/ 13 декабря 2017

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

0 голосов
/ 18 января 2013

Во всех ваших решениях не учитывается, что произойдет, если узел будет вставлен в середину дерева. Вы предполагаете, что оно также будет самым маленьким или самым большим. Когда вы вставите что-то в середину дерева, вы поймете, что операция становится более сложной.

0 голосов
/ 05 августа 2011

Вместо:

if (dataIn <= nodeIn.getLeft().getData()) {

... вы хотите:

if (dataIn < nodeIn.getData()) {

Вам необходимо сравнить значение, которое должно быть вставлено, со значением в текущем узле.

Я изменил знак <= на знак <, чтобы избежать дублирования.

Итак, ваш код рефакторинга:

public void insert(int dataIn) {
  root = insert(root, dataIn);
}

private Node insert(Node nodeIn, int dataIn){
  if (nodeIn == null) {
    nodeIn = new Node(null, null, dataIn);
  } else {
    if (dataIn < nodeIn.getData()) {
      nodeIn.setLeft(insert(nodeIn.getLeft(), dataIn));
    } else {
      nodeIn.setRight(insert(nodeIn.getRight(), dataIn));
    }
  }
  return nodeIn;
}
...