Home > Enterprise >  Binary Search Tree implementation problem
Binary Search Tree implementation problem

Time:09-17

I've got this BST I've built and trying to follow java code conventions I decided to fix around some of the access modifiers and add some getters and setters but now my entire code is giving me lots of problems in the execution and I cannot figure out why.

This is my Node class.

/**
 * A class that implements a binary tree's node. It contains the data inside each node of the tree.
 */
public class Node {
  private int data;
  private Node left;
  private Node right;

  /**
   * Constructor initializing the data of the node.
   *
   * @param data The numeric value of each node as an Integer.
   */
  public Node(int data) {
    this.data = data;
    this.left = null;
    this.right = null;
  }

  public int getData() {
    return data;
  }

  public void setData(int data) {
    this.data = data;
  }

  public Node getLeft() {
    return left;
  }

  public void setLeft(Node left) {
    this.left = left;
  }

  public Node getRight() {
    return right;
  }

  public void setRight(Node right) {
    this.right = right;
  }
}

This is the tree class.

import java.util.ArrayList;
import java.util.List;

/** Class implementation of a binary tree , containing helper classes and methods. */
public class BinaryTree {
  private Node root;
  private List<Integer> nodes = new ArrayList<>();
  /** Constructor initializing the root node of the tree. */
  public BinaryTree() {
    root = null;
  }

  public Node getRoot() {
    return root;
  }

  private Node insertNode(Node node, int dataBeingInserted) {
    if (node == null) {
      node = new Node(dataBeingInserted);
      return node;
    }
    if (node.getData() > dataBeingInserted) {
      insertNode(node.getLeft(), dataBeingInserted);
    } else if (node.getData() < dataBeingInserted) {
      insertNode(node.getRight(), dataBeingInserted);
    }
    return node;
  }

  /**
   * Method that inserts nodes into the binary tree. If the tree is empty , a new root node is
   * initialized.
   *
   * @param dataBeingInserted The number to be inserted as an integer.
   */
  public void insertNode(int dataBeingInserted) {
    root = insertNode(root, dataBeingInserted);
  }

  private Node searchTree(Node node, int dataBeingSearched) {
    if (node == null || node.getData() == dataBeingSearched) {
      return node;
    }
    if (node.getData() > dataBeingSearched) {
      return searchTree(node.getLeft(), dataBeingSearched);
    }
    return searchTree(node.getRight(), dataBeingSearched);
  }
  /**
   * Method that recursively searches for our element through the tree. If the value is present in
   * the root node , or there aren't any nodes in the tree , the method returns the root node. If
   * the value we're looking for is smaller than the root node's value , we search for our value in
   * the left subtree , otherwise we search for it in the right subtree.
   *
   * @param dataBeingSearched User's value.
   * @return Recursive call of the method.
   */
  public Node searchTree(int dataBeingSearched) {
    return searchTree(root, dataBeingSearched);
  }

  private String inorderTraversal(Node node) {
    if (node == null) {
      return "";
    }
    inorderTraversal(node.getLeft());
    nodes.add(node.getData());
    inorderTraversal(node.getRight());
    return nodes.toString();
  }

  /**
   * An implementation of the In-order traversal. First the left subtree is visited and printed
   * accordingly, then we visit and print the root and after that we visit and print the right
   * subtree.
   */
  public String inorderTraversal() {
    return inorderTraversal(root);
  }
}

And those are some tests I wrote just to try some stuff.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/** Binary tree operations tests. */
class BinaryTreeTests {
  /** Testing whether the answer is correct if we search for the root value of the tree. */
  @Test
  void isSearchWorking() {
    BinaryTree tree = new BinaryTree();
    tree.insertNode(10);
    tree.insertNode(30);
    tree.insertNode(35);
    tree.insertNode(29);
    assertEquals(tree.getRoot(), tree.searchTree(20));
  }

  /** Testing whether the root changes it's value from null after a single insertion. */
  @Test
  void isInsertWorking() {
    BinaryTree tree = new BinaryTree();
    assertNotNull(tree.getRoot());
  }

  @Test
  void inOrderTraversalPrint() {
    BinaryTree tree = new BinaryTree();
    tree.insertNode(10);
    tree.insertNode(30);
    tree.insertNode(35);
    tree.insertNode(29);
    assertEquals("[10, 20, 29, 30, 35]", tree.inorderTraversal());
  }

  @Test
  void inOrderTraversalSameElement() {
    BinaryTree tree = new BinaryTree();
    tree.insertNode(1);
    tree.insertNode(1);
    tree.insertNode(1);
    tree.insertNode(1);
    tree.insertNode(1);
    tree.insertNode(1);
    assertEquals("[1]", tree.inorderTraversal());
  }

}

So before I set the data , left and right variables in the Node class to public , everything was working just fine , now that they are private , only the last test passes for some reason.

isInsertWorking() is giving me expected not

inOrderTraversalPrint() is giving me just [10] instead of [10, 20, 29, 30, 35]

isSearchWorking() says expected node got null.

I currently do not know how to handle these things , I think my recursions might be incorrect but I cannot think of a way to fix them.

CodePudding user response:

The main problem was in insertNode() function which I have fixed. There was a bug in searchTree() function and also I cleared the list nodes whenever inorderTraversal() is called since the tree can be modified between two inorderTraversal() calls.

import java.util.ArrayList;
import java.util.List;
/**
 * A class that implements a binary tree's node. It contains the data inside each node of the tree.
 */
class Node {
    private int data;
    private Node left;
    private Node right;

    /**
     * Constructor initializing the data of the node.
     *
     * @param data The numeric value of each node as an Integer.
     */
    public Node(int data) {
        this.data = data;
        this.left = null;
        this.right = null;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }
}

/** Class implementation of a binary tree , containing helper classes and methods. */
class BinaryTree {
    private Node root;
    private List<Integer> nodes = new ArrayList<>();
    /** Constructor initializing the root node of the tree. */
    public BinaryTree() {
        root = null;
    }

    public Node getRoot() {
        return root;
    }

    private Node insertNode(Node node, int dataBeingInserted) {
        if (node == null)
            return new Node(dataBeingInserted);

        if (node.getData() == dataBeingInserted)
            return root;

        if (node.getData() < dataBeingInserted) {
            if (node.getRight() != null)
                return insertNode(node.getRight(), dataBeingInserted);
            else
                node.setRight(new Node(dataBeingInserted));
        } else if (node.getData() > dataBeingInserted) {
            if (node.getLeft() != null)
                return insertNode(node.getLeft(), dataBeingInserted);
            else
                node.setLeft(new Node(dataBeingInserted));
        }
        return root;
    }

    /**
     * Method that inserts nodes into the binary tree. If the tree is empty , a new root node is
     * initialized.
     *
     * @param dataBeingInserted The number to be inserted as an integer.
     */
    public void insertNode(int dataBeingInserted) {
        root = insertNode(root, dataBeingInserted);
    }

    private Node searchTree(Node node, int dataBeingSearched) {
        if (node == null || node.getData() == dataBeingSearched) {
            return node;
        }
        if (node.getData() > dataBeingSearched) {
            return searchTree(node.getLeft(), dataBeingSearched);
        } else {
            return searchTree(node.getRight(), dataBeingSearched);
        }
    }
    /**
     * Method that recursively searches for our element through the tree. If the value is present in
     * the root node , or there aren't any nodes in the tree , the method returns the root node. If
     * the value we're looking for is smaller than the root node's value , we search for our value in
     * the left subtree , otherwise we search for it in the right subtree.
     *
     * @param dataBeingSearched User's value.
     * @return Recursive call of the method.
     */
    public Node searchTree(int dataBeingSearched) {
        return searchTree(root, dataBeingSearched);
    }

    private String inorderTraversal(Node node) {
        if (node == null) {
            return "";
        }
        inorderTraversal(node.getLeft());
        nodes.add(node.getData());
        inorderTraversal(node.getRight());
        return nodes.toString();
    }

    /**
     * An implementation of the In-order traversal. First the left subtree is visited and printed
     * accordingly, then we visit and print the root and after that we visit and print the right
     * subtree.
     */
    public String inorderTraversal() {
        nodes.clear();  // clear the previous state
        return inorderTraversal(root);
    }
}
  • Related