I have a project I am working on that involves making a database of movies. I have a Movie object and my problem is that I am having trouble printing out Movies that have the same title. Currently only one of the movies is being printed out. I am sure my search function in my BinarySearchTree class is working because it finds it correctly, I think it is stopping once the search condition is met and it doesn't look for any other possible movies with the same title. I think to solve this I just need to implement a loop that will print out each movie as as it is found when traversing the BinarySearchTree.
Here is my search function in BinarySearchTree:
public Node search( Movie m ){
if ( root == null ){
System.out.println("No items to search.");
return null;
}else{
return search( m, root );
}
}
private Node search( Movie m, Node n){
if ( m.compareTo( n.getData() ) == 0 ){
if(n.getLeft() != null){//Go left to continue searching
Node node = search(m, n.getLeft());
if(node != null)
return node;
}
return n;
}else{
if ( n.getRight() == null ){
System.out.println("Item not found.");
return null;
}else{
return search(m, n.getRight());
}
}
}
The implementation in my Main that currently only prints out only one of the movies with the same title (the first one it comes across). I need a loop I think or some way to keep iterating through the tree.
public static BinarySearchTree findByTitle( BinarySearchTree tree ){
Scanner input = new Scanner(System.in);
System.out.println("Enter the title of the movie: ");
Movie temp = new Movie( input.nextLine() );
Node leftMost = tree.search(temp);
if( leftMost != null ){
while(leftMost != null && temp.compareTo( leftMost.getData() ) == 0){
System.out.println(leftMost.getData());
leftMost = leftMost.getRight();
}
}
return tree;
}
First, you can get the left most entry by modifying the search function:
private Node search( Movie m, Node n){
if ( m.compareTo( n.getData() ) == 0 ){
if(n.getLeft() != null){//Go left to continue searching
Node node = search(m, n.getLeft());
if(node != null)
return node;
}
return n;
}
if ( m.compareTo( n.getData() ) < 0 ){
if( n.getLeft() == null){
System.out.println("Item not found.");
return null;
}else{
return search(m, n.getLeft());
}
}else{
if ( n.getRight() == null ){
System.out.println("Item not found.");
return null;
}else{
return search(m, n.getRight());
}
}
After getting the left most node, just keep getting to the right until the movie's title is not equals.
Node leftMost = search(m);
if(leftMost != null){
while(leftMost != null && m.compareTo(leftMost.getData()) == 0){
System.out.println(leftMost.getData());
leftMost = leftMost.getRight();
}
}
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
I have a Java task where I have to create a splay tree which requires me to find the parent and grandparent node of the node I am accessing. To do this, I've chosen to create a findParent method. Here is my Node class.
public class Node<T>
{
public T elem = null;
public Node<T> left = null;
public Node<T> right = null;
public Node(T elem) {
this.elem = elem;
}
public String toString() {
String out = elem.toString();
out += " [L: "+ (left == null ? "null" : left.elem) + "] ";
out += " [R: "+ (right == null ? "null" : right.elem) + "] ";
return out;
}
}
I am not allowed to change the Node class. My SplayTree class is made up of these nodes and inside the SplayTree class, I have my findParent function.
public Node<T> findParent(Node<T> A) {
Node<T> P = root;
if (P.left == A || P.right == A) {
return P;
} else if (A.elem.compareTo(P.elem) < 0) {
P = P.left;
} else {
P = P.right;
}
return null;
}
To test the code, I've entered the following numbers in order into the tree "50, 25, 100, 5, 110, 115, 75, 42, 101, 112". The insert method follows the normal BST insert rules of having larger elements on the right and smaller elements on the left. I tested my findParent method using the node containing 110 as the target so theoretically, it should return 100 as the parent and to get the grandparent, I would use findParent(parent) which should return 50 but instead, I get a nullptr exception. I've tested my insert function to see if I am populating my tree correctly, however, that is not the case as the insert method works correctly.
you can do it recursively but it may crashes the executing thread with StackOverFlow exception on large data sets
public Node<T> findParent(Node<T> node, Node<T> n){
if(node == null) return null;
if(node.right == n || node.left == n){
return node;
}else{
Node<T> r = findParent(node.left, n);
if(r == null){
r = findParent(node.right, n);
}
return r;
}
}
public Node<T> findParent(Node<T> n){
if(n == null)
throw new NullPointerException("arg0 cannot be Null");
return findParent(root, n);
}
for large data sets you should have some sort of Stack machine to traverse all the nodes:
public Node<Object> findParent(Node<T> root, Node<T> node){
Stack<Node<T>> stack = new Stack<>();
stack.push(root);
while(stack.size() > 0){
Node<T> p = stack.pop();
if(p.right == node || p.left == node){
return p;
}else{
if(p.left != null){
stack.push(p.left);
}else if(p.right != null){
stack.push(p.right);
}else{
Node<T> parent = null;
if(stack.size() > 0)
parent = stack.peek();
if(parent == null){
break;
}else if(parent.left == p){
if(parent.right != null){
stack.push(parent.right);
}
}else if(parent.right == p){
stack.pop();
}
}
}
}
return null;
}
both tested with your data structure.
in the second example at line 10, if you return the Stack<Node> you can have all the parents in a row
I have the following insert method for inserting into an AVL tree.
if(node == null){
node = new AVLTreeNode(key);
}
else if (key == node.getKey()){
//do nothing, duplicate key
}
else if (key<node.getKey()){
node.setLeft(insert(node.getLeft(), key));
if(node.getBalanceFactor() == 2){
if(key< node.getLeft().getKey()){
node = rotateWithLeftChild(node);
}
else{
node = doubleRotateWithLeftChild(node);
}
}
}
else {
node.setRight(insert(node.getRight(), key));
if(node.getBalanceFactor() == -2){
if(key> node.getRight().getKey()){
node = rotateWithRightChild(node);
}
else{
node = doubleRotateWithRightChild(node);
}
}
}
//set node height to max children+1
if(node.hasLeft() && node.hasRight()){
node.setHeight(Math.max(node.getLeft().getHeight(), node.getRight().getHeight())+1);
}
else if(node.hasLeft() && node.hasRight() == false){
node.setHeight(node.getLeft().getHeight()+1);
}
else if(node.hasRight() && node.hasLeft() == false){
node.setHeight(node.getRight().getHeight()+1);
}
else{
node.setHeight(1);
}
return node;
and then I have the rotate right method that looks like this:
public static AVLTreeNode rotateWithRightChild( AVLTreeNode k1 )
{
AVLTreeNode k2 = k1.getRight();
k1.setRight(k2.getLeft());
k2.setLeft(k1);
k1.setHeight(Math.max(k1.getLeft().getHeight(), 0)+1);
k2.setHeight(Math.max(k2.getRight().getHeight(), k1.getHeight())+1);
return k2;
}
However the if I insert 1 then 2 then 3, I get an error because I have a Null Pointer, it seems the rotate method is working on the last node with key 3 rather than its parent, so im not sure how to fix this as there is no getParent() method provided in the framework. Any suggestions?
I am trying to implement a remove method for the BST structure that I have been working on. Here is the code with find, insert, and remove methods:
public class BST {
BSTNode root = new BSTNode("root");
public void insert(BSTNode root, String title){
if(root.title!=null){
if(title==root.title){
//return already in the catalog
}
else if(title.compareTo(root.title)<0){
if(root.leftChild==null){
root.leftChild = new BSTNode(title);
}
else{
insert(root.leftChild,title);
}
}
else if(title.compareTo(root.title)>0){
if(root.rightChild==null){
root.rightChild = new BSTNode(title);
}
else{
insert(root.rightChild,title);
}
}
}
}
public void find(BSTNode root, String title){
if(root!= null){
if(title==root.title){
//return(true);
}
else if(title.compareTo(root.title)<0){
find(root.leftChild, title);
}
else{
find(root.rightChild, title);
}
}
else{
//return false;
}
}
public void remove(BSTNode root, String title){
if(root==null){
return false;
}
if(title==root.title){
if(root.leftChild==null){
root = root.rightChild;
}
else if(root.rightChild==null){
root = root.leftChild;
}
else{
//code if 2 chlidren remove
}
}
else if(title.compareTo(root.title)<0){
remove(root.leftChild, title);
}
else{
remove(root.rightChild, title);
}
}
}
I was told that I could use the insert method to help me with the remove method, but I am just not seeing how I can grab the smallest/largest element, and then replace the one I am deleting with that value, then recursively delete the node that I took the replacement value, while still maintaining O(logn) complexity. Anyone have any ideas or blatant holes I missed, or anything else helpful as I bang my head about this issue?
EDIT:
I used the answers ideas to come up with this, which I believe will work but I'm getting an error that my methods (not just the remove) must return Strings, here is what the code looks like, I thought that's the return statements??
public String remove(BSTNode root, String title){
if(root==null){
return("empty root");
}
if(title==root.title){
if(root.leftChild==null){
if(root.rightChild==null){
root.title = null;
return(title+ "was removed");
}
else{
root = root.rightChild;
return(title+ "was removed");
}
}
else if(root.rightChild==null){
root = root.leftChild;
return(title+ "was removed");
}
else{
String minTitle = minTitle(root);
root.title = minTitle;
remove(root.leftChild,minTitle);
return(title+ "was removed");
}
}
else if(title.compareTo(root.title)<0){
remove(root.leftChild, title);
}
else{
remove(root.rightChild, title);
}
}
public void remove (String key, BSTNode pos)
{
if (pos == null) return;
if (key.compareTo(pos.key)<0)
remove (key, pos.leftChild);
else if (key.compareTo(pos.key)>0)
remove (key, pos.rightChild);
else {
if (pos.leftChild != null && pos.rightChild != null)
{
/* pos has two children */
BSTNode maxFromLeft = findMax (pos.leftChild); //need to make a findMax helper
//"Replacing " pos.key " with " maxFromLeft.key
pos.key = maxFromLeft.key;
remove (maxFromLeft.key, pos.leftChild);
}
else if(pos.leftChild != null) {
/* node pointed by pos has at most one child */
BSTNode trash = pos;
//"Promoting " pos.leftChild.key " to replace " pos.key
pos = pos.leftChild;
trash = null;
}
else if(pos.rightChild != null) {
/* node pointed by pos has at most one child */
BSTNode trash = pos;
/* "Promoting " pos.rightChild.key" to replace " pos.key */
pos = pos.rightChild;
trash = null;
}
else {
pos = null;
}
}
}
This is the remove for an unbalanced tree. I had the code in C++ so I have quickly translated. There may be some minor mistakes though. Does the tree you are coding have to be balanced? I also have the balanced remove if need be. I wasn't quite sure based on the wording of your question. Also make sure you add a private helper function for findMax()
void deleteTreeNode(int data){
root = deleteTreeNode(root ,data);
}
private TreeNode deleteTreeNode(TreeNode root, int data) {
TreeNode cur = root;
if(cur == null){
return cur;
}
if(cur.data > data){
cur.left = deleteTreeNode(cur.left, data);
}else if(cur.data < data){
cur.right = deleteTreeNode(cur.right, data);
}else{
if(cur.left == null && cur.right == null){
cur = null;
}else if(cur.right == null){
cur = cur.left;
}else if(cur.left == null){
cur = cur.right;
}else{
TreeNode temp = findMinFromRight(cur.right);
cur.data = temp.data;
cur.right = deleteTreeNode(cur.right, temp.data);
}
}
return cur;
}
private TreeNode findMinFromRight(TreeNode node) {
while(node.left != null){
node = node.left;
}
return node;
}
To compare objects in java use .equals() method instead of "==" operator
if(title==root.title)
^______see here
you need to use like this
if(title.equals(root.title))
or if you are interesed to ignore the case follow below code
if(title.equalsIgnoreCase(root.title))
private void deleteNode(Node temp, int n) {
if (temp == null)
return;
if (temp.number == n) {
if (temp.left == null || temp.right == null) {
Node current = temp.left == null ? temp.right : temp.left;
if (getParent(temp.number, root).left == temp)
getParent(temp.number, root).left = current;
else
getParent(temp.number, root).right = current;
} else {
Node successor = findMax(temp.left);
int data = successor.number;
deleteNode(temp.left, data);
temp.number = data;
}
} else if (temp.number > n) {
deleteNode(temp.left, n);
} else {
deleteNode(temp.right, n);
}
}
I know this is a very old question but anyways... The accepted answer's implementation is taken from c++, so the idea of pointers still exists which should be changed as there are no pointers in Java. So every time when you change the node to null or something else, that instance of the node is changed but not the original one This implementation is taken from one of the coursera course on algorithms.
public TreeNode deleteBSTNode(int value,TreeNode node)
{
if(node==null)
{
System.out.println("the value " + value + " is not found");
return null;
}
//delete
if(node.data>value) node.left = deleteBSTNode(value,node.left);
else if(node.data<value) node.right = deleteBSTNode(value,node.right);
else{
if(node.isLeaf())
return null;
if(node.right==null)
return node.left;
if(node.left==null)
return node.right;
TreeNode successor = findMax(node.left);
int data = successor.data;
deleteBSTNode(data, node.left);
node.data = data;
}
return node;
}
All the links between the nodes are pertained using the return value from the recursion.
For the Depth First Post-Order traversal and removal, use:
/*
*
* Remove uses
* depth-first Post-order traversal.
*
* The Depth First Post-order traversal follows:
* Left_Child -> Right-Child -> Node convention
*
* Partial Logic was implemented from this source:
* https://stackoverflow.com/questions/19870680/remove-method-binary-search-tree
* by: sanjay
*/
#SuppressWarnings("unchecked")
public BinarySearchTreeVertex<E> remove(BinarySearchTreeVertex<E> rootParameter, E eParameter) {
BinarySearchTreeVertex<E> deleteNode = rootParameter;
if ( deleteNode == null ) {
return deleteNode; }
if ( deleteNode.compareTo(eParameter) == 1 ) {
deleteNode.left_child = remove(deleteNode.left_child, eParameter); }
else if ( deleteNode.compareTo(eParameter) == -1 ) {
deleteNode.right_child = remove(deleteNode.right_child, eParameter); }
else {
if ( deleteNode.left_child == null && deleteNode.right_child == null ) {
deleteNode = null;
}
else if ( deleteNode.right_child == null ) {
deleteNode = deleteNode.left_child; }
else if ( deleteNode.left_child == null ) {
deleteNode = deleteNode.right_child; }
else {
BinarySearchTreeVertex<E> interNode = findMaxLeftBranch( deleteNode.left_child );
deleteNode.e = interNode.e;
deleteNode.left_child = remove(deleteNode.left_child, interNode.e);
}
} return deleteNode; } // End of remove(E e)
/*
* Checking right branch for the swap value
*/
#SuppressWarnings("rawtypes")
public BinarySearchTreeVertex findMaxLeftBranch( BinarySearchTreeVertex vertexParameter ) {
while (vertexParameter.right_child != null ) {
vertexParameter = vertexParameter.right_child; }
return vertexParameter; } // End of findMinRightBranch
Im working on a "family tree" program in java, and I am having trouble wrapping my head around an algorithm for searching through the nodes.
A node consists of a Name, and link to a partner, sibling, child and an integer identifier.
The algorithms I am trying just hit dead ends and I would be extremely grateful for a nudge in the right direction.
Basically, with each node having a a numerical identifier, I want to be able to have the user enter a number, search each node in the tree and insert a node as a child, sibling or partner of the matching node.
Tree structure example:
Note, as it is an assignment I cannot change the structure
Alice[2] <--partner-- John[1]
|
Ted[3] --sibling--> Eric[4] --sibling--> Joanne[5]
|
Joe[6] --sibling--> Bret[7]
FamilyTree Class:
public class FamilyTree {
private class FamilyTreeNode{
private int identifier ;
private String Name ;
private FamilyTreeNode partner;
private FamilyTreeNode sibling;
private FamilyTreeNode child;
}
private FamilyTreeNode ancestor;
private FamilyTreeNode currentNode ;
private int indexNumber = 1;
public FamilyTree(){
this.ancestor = new FamilyTreeNode();
this.ancestor.Name = Input.getString("Enter ancestors Name: ");
this.ancestor.identifier = 0;
}
public FamilyTreeNode addChild(){
//Set up variables and create new node
currentNode = ancestor;
boolean matchFound = false ;
FamilyTreeNode newFamilyNode = new FamilyTreeNode() ;
newFamilyNode.Name = Input.getString("Enter Name");
//
//Checking for existing Name
if(currentNode.child != null){
currentNode = currentNode.child;
if(currentNode.Name.compareToIgnoreCase(newFamilyNode.Name) == 0){
matchFound = true;
}
while(currentNode.sibling != null){
currentNode = currentNode.sibling;
if(currentNode.Name.compareToIgnoreCase(newFamilyNode.Name) == 0){
matchFound = true;
}
}
}
//
//Check for existing siblings, add to end of list
currentNode = ancestor;
if(currentNode.child == null){
newFamilyNode.identifier = indexNumber;
currentNode.child = newFamilyNode ;
}else{
currentNode = currentNode.child;
while (currentNode.sibling != null){
currentNode = currentNode.sibling;}
if(matchFound == false){
indexNumber++;
newFamilyNode.identifier = indexNumber;
currentNode.sibling = newFamilyNode;
}
else{
System.out.println("Name already exists");
}
}
//
return newFamilyNode ;
}
public FamilyTreeNode addPartner(){
currentNode = ancestor ;
FamilyTreeNode newPartnerNode = new FamilyTreeNode() ;
int currentNodeIdentifier;
int partnerIdentifier;
boolean insertPointFound = false ;
display();
partnerIdentifier = Input.getInteger("Input partner ID");
while(insertPointFound == false){
if(partnerIdentifier == currentNode.identifier){
}else{
currentNode
}
}
return newPartnerNode;
}
public void display(){
currentNode = ancestor;
System.out.println(currentNode.Name + " " + currentNode.identifier);
if(currentNode.child != null){
currentNode = currentNode.child;
System.out.println(currentNode.Name + " " + currentNode.identifier);
while(currentNode.sibling != null){
currentNode = currentNode.sibling;
System.out.println(currentNode.Name + " " + currentNode.identifier);
}
}
}
}
Assuming that all the identifiers are unique, you can achieve searching using any tree traversal algorithm. Here is a sample DFS that would solve your problem (you can modify this function as per your requirement).
boolean[] visited = new boolean[n]; // n is no. of nodes in the tree
public FamilyTreeNode dfs(FamilyTreeNode root, int searchKey) {
if(root == null) {
return null;
}
if(root.identifier == searchKey) {
return root;
}
visited[root.identifier] = true;
FamilyTreeNode next = null;
if((root.partner != null) && (!visited[root.partner.identifier])) {
next = dfs(root.partner, searchKey);
}
if(next != null) return next;
if((root.sibling != null) && (!visited[root.sibling.identifier])) {
next = dfs(root.sibling, searchKey);
}
if(next != null) return next;
if((root.child != null) && (!visited[root.child.identifier])) {
next = dfs(root.child, searchKey);
}
return next;
}
I need to create a recursive method that takes as a parameter the root node of a binary search tree. This recursive method will then return the int value of the total number of nodes in the entire binary search tree.
This is what I have so far:
public class BinarySearchTree<E> extends AbstractSet<E>
{
protected Entry<E> root;
//called by the main method
public int nodes()
{
return nodes(root);
}
//nodes() will count and return the nodes in the binary search tree
private int nodes(Entry<E> current)
{
if(current.element != null)
{
if(current.left == null && current.right == null)
{
if(current.element == root.element)
return 1;
deleteEntry(current);
return 1 + nodes(current.parent);
}
else if(current.left != null && current.right == null)
return nodes(current.left);
else if(current.left == null && current.right != null)
return nodes(current.right);
else if(current.left != null && current.right != null)
return nodes(current.left) + nodes(current.right);
} else return 1;
return 0;
}
The main method calls nodes like so:
System.out.println ("\nThis section finds the number of nodes "
+ "in the tree");
System.out.println ("The BST has " + bst.nodes() + " nodes");
So I was running the search by traveling in order, once I'd get to a node with no children I would delete the current node and return to the parent node and continue. I ran a debug of the method I have above and the program crashes with a NullPointerException() when it finally counts and removes all the nodes on the left and right side of the root node and tries to return 1.
This is for my lab, the method MUST be recursive.
I'm very lost at this point, does anyone know what I'm doing wrong?
You are making this way too complicated. The basic idea of object oriented programming is that you trust objects to do the jobs they know the answers to. So if I'm a parent, I can count myself, and I let my children count themselves, and so forth.
private int nodes(Entry<E> current) {
// if it's null, it doesn't exist, return 0
if (current == null) return 0;
// count myself + my left child + my right child
return 1 + nodes(current.left) + nodes(current.right);
}
You have several issues:
You're deleting nodes as you count them? Is nodes() supposed to clear the tree?
You're treating root==null, root!=null&left==null&&right==null, root!=null&left!=null&right==null, etc as separate cases. They're not. You have three cases, which are not entirely exclusive:
If the current node is not null, add one to the count. (This should always be the case. The only case where it might be false is if the current node == root, and we can detect and sidestep that beforehand.)
If the current node has a left child, add the left child's count.
If the current node has a right child, add the right child's count.
You're traversing back up the tree for some ungodly reason. Looks like it has something to do with deleting nodes...?
But the biggest thing in my opinion is, you're not giving enough autonomy to the Entrys. :P
A node can count its own children. Trust it to.
class Entry<E> {
...
int count() {
int result = 1;
if (left != null) result += left.count();
if (right != null) result += right.count();
return result;
}
}
public int nodes() {
return (root == null) ? 0 : root.count();
}
If your teacher is incompetent, and insists on some node-counting function outside a node, you can do the same thing you were trying to do:
private int nodes(Entry<E> current) {
int result = 1;
if (current.left) result += nodes(current.left);
if (current.right) result += nodes(current.right);
return result;
}
public int nodes() {
return (root == null) ? 0 : nodes(root);
}
But that teacher should be fired, in my opinion. The Entry class is the real tree; BinarySearchTree is really just a container for a reference to the root.
Also notice, i don't give a damn about the parents. If we start counting from the root, and each node counts its children, which count their children, etc etc... then all nodes will be accounted for.
public int countNodes(Node root){
// empty trees always have zero nodes
if( root == null ){
return 0;
}
// a node with no leafes has exactly one node
// note from editor: this pice of code is a micro optimization
// and not necessary for the function to work correctly!
if( root.left == null && root.right == null ){
return 1;
}
// all other nodes count the nodes from their left and right subtree
// as well as themselves
return countNodes( root.left ) + countNodes( root.right ) + 1;
}
After you delete current in: deleteEntry(current);, you use current.parent in return 1 + nodes(current.parent);
May be this's the reason of throwing NullPointerException..
Hey I have a very clean counting implemented for a binary tree:
public class Binary<T> where T: IComparable<T>
{
private Node _root;
public int Count => _root.Count;
public void Insert(T item)
{
Node newNode = new Node(item);
if (_root == null)
_root = newNode;
else
{
Node prevNode = _root;
Node treeNode = _root;
while (treeNode != null)
{
prevNode = treeNode;
treeNode = newNode.Item.CompareTo(treeNode.Item) < 1 ? treeNode.Left : treeNode.Right;
}
newNode.Parent = prevNode;
if (newNode.Item.CompareTo(prevNode.Item) < 1)
prevNode.Left = newNode;
else
prevNode.Right = newNode;
}
}
public class Node
{
public T Item;
public Node Parent;
public Node Left;
public Node Right;
public Node(T item, Node parent = null, Node left = null, Node right = null)
{
Item = item;
Parent = parent;
Left = left;
Right = right;
}
public int Count
{
get
{
int count = 1;
count += Left?.Count ?? 0;
count += Right?.Count ?? 0;
return count;
}
}
}
}
Maybe this helps you to understand how to implement a class for a simple binary tree with a count.
This implementation accesses the count through a count in the corresponding node in the tree.
Let me now if you are not familiar with the markup of .NET 4.6