简体   繁体   中英

inserting nodes into a binary tree in java question

im coming from c++ to java and i am confused on binary trees with java. is the only way to have a Node class is to make it an inner static class? all the examples i see do this. However, the way im doing it is i have a node class and a binarytree class uses this node class. but i keep getting an error when i try inserting into the tree after the second insert. i get an exception at this line if(dataIn <= nodeIn.getLeft().getData()){

I am confused as to what i did wrong.... here is my code for insert that i have. thanks in advance..

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

Part of the reason it's confusing is that "Node" should not be a parameter to the insert method, you should be calling an insert method defined in node.

So let's say you hold the "Root" node in your "normal code"--let's call it "rootNode" just to be obscure.

Okay, so your code to insert into the tree would be:

rootNode.insert(newValue);

Easy enough.

Now to define that method.

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

This should read much more clearly. I'm going to hit "Post" then I'm going to edit it and figure out how to easily refractor that evil evil copy & paste code.

On second thought, I'll leave it there because it's more readable. The best fix I can see is to make the nodes an array, then you get:

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

But I won't replace the original because, as I said, it's clearer.

I recommend the refactoring book for more of this. It really does help simplify your code once you really get OO. Passing an object to an otherwise static method (one that doesn't use member variables) is a dead give-away.

With more considerations about @ted's comment and OO--getLeft and getRight shouldn't even be an issue. Neither is necessary outside the abstraction.

In general what you probably need is these methods in Node:

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

and maybe

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

Then you don't even need to expose that it's a tree you are dealing with--beter OO abstraction.

您需要测试nodeIn.getLeft() == null

you can use the below code to clear your understanding. Mostly we do not use any other class everything can be done inside a single Node class itself. here is a very basic example which i believe might be helpful... Also when i see you have two methods in which you have only provided data rather than root. Trust me it is better to have root in your main class. reasoning we have it handy where ever we need to cache.

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;

}

directly call this method from any class where you have initialized. here is a sample plz check..

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

is the only way to have a Node class is to make it an inner static class? all the examples i see do this.

No.

The Node class doesn't need to be an inner or nested class. (Strictly speaking a "static inner" class is a nested class.)

However, only an inner or nested class can be private . If your Node class is a regular class you are exposing implementation details to (at least) other classes in the same package. This is a bad idea ... and that explains why you see the Node class declared the way it is.

Actually, for a binary tree there is no need to check whether the inserting element is either greater than or left than the parent node. I think there is no need of checking those conditions. We have to take the input from user whether to insert right or left.

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

Instead of:

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

... you want:

if (dataIn < nodeIn.getData()) {

You need to compare the value that is to be inserted with the value at the current node.

I changed the <= sign to a < sign so that duplicates are avoided.

So your code refactored is:

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

All your solutions do not take into accoount what would happen if the node was to be inserted in the middle of the tree. You are assuming that it will also be smallest or greatest. When you insert something in the middle of the tree, then you will realize that the operation becomes more complex.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM