Binary Tree Search for non key value - java

I am currently looking for an recursive algorithm to find a non key value in my Tree.
I have my Node Class:
public class TreeNode {
private Person person;
private TreeNode left, right;
public TreeNode(Person person) {
this.person = person;
}
public boolean insert(Person person) {
if (person.getAge() < this.person.getAge()){
if (left != null){
return left.insert(person);
}else {
left = new TreeNode(person);
}
}else{
if (right != null){
return right.insert(person);
}else{
right = new TreeNode(person);
}
}
return true;
}
public boolean countryExists(String country){
if (!this.person.getCountry().equals(country)){
if (right != null) {
return right.countryExists(country);
}
if (left != null) {
return left.countryExists(country);
}
}else {
return true;
}
}
}
The Key value here is the age of a person. I want to find out if there is a Person which comes from a specific country. Therefore I made the function countryExists(String country) I don't know how to implement this and I have searched everywhere and watched a lot of videos about post/pre/inorder. The ordering shouldn't be a problem? I have an issue with returning the correct boolean I think...
Thank you for your help.

In your countryExists method you should return false after two != null checks, because if execution came to this point it means that your node doesn't have left and right siblings (it's a leaf) and it's persons's country doesn't equal to the one you're looking for.
But I would suggest doing some refactoring, and instead of negating this.person.getCountry().equals(country), just use it and return true at the beginning of the method.
public boolean countryExists(String country) {
if (this.person.getCountry().equals(country)) {
return true;
}
if (right != null) {
return right.countryExists(country);
}
if (left != null) {
return left.countryExists(country);
}
return false;
}
Also, this is O(n) solution, because you're not using a key to cut off entire branches, and doing full tree traversal.
To make it O(log n) (in the case when the tree is balanced), you need to use country as key and choose only one branch when searching.

Related

When to use return in recursive function?

I'm learning the BST recursive construction and found that the insert method does not use return keyword when implementing recursion, but the contains method do use the return key word. Can anybody explain this to me? Many thanks!
static class BST {
public int value;
public BST left;
public BST right;
public BST(int value) {
this.value = value;
}
public BST insert(int value) {
// Write your code here.
// Do not edit the return statement of this method.
if (value < this.value) {
if (left == null) {
BST newBST = new BST(value);
left = newBST;
} else {
left.insert(value);
}
} else {
if (right == null) {
BST newBST = new BST(value);
right = newBST;
} else {
right.insert(value);
}
}
return this;
}
public boolean contains(int value) {
// Write your code here.
if (value < this.value) {
if (left == null) {
return false;
} else {
return left.contains(value);
}
} else if (value > this.value) {
if (right == null) {
return false;
} else {
return right.contains(value);
}
} else{
return true;
}
}
Essentially because insert is not implemented as a function but contains is, meaning that insert just has side effects, it changes the state of BST. Contains is inherently a function - it returns an answer for a given input.
The fact insert returns this at the end is not necessary, it could just as easily have a void return value.
A functional version would return a new BST that is like the original but with the element inserted, and that would require use of the returned value, there would be a bit more complexity there.
(I'm not advocating a functional version here!)
The "insert" function only has a return statement right at the end, because all it has to return is "this", rather than being dependent on outside factors and the execution of the function.
So, short version: You use "return" when you need to, and you do not use "return" when you do not need to.

Unusual Java implementation of red/black tree node insertion

I'm writing a program for class in Java regarding red/black trees. I've got a good understanding of how they usually work, and am supposed to use a recursive insertion method. What I would typically use is below, to match my professor's Node class. In regards to color, a 0 is black, a 1 is red. The Node class given to us does not deal with keys at all.
private static void put(int val, int col)
{ root = put(root, val, col); }
private static Node put(Node n, Integer val, int col)
{
if (n == null){
Node t=new Node(val);
t.setColor(1);
return t;
}
int cmp = val.compareTo(n.getValue());
if (cmp < 0) n.setLeft(put(n.getLeft(), val, col));
else if (cmp > 0) n.setRight(put(n.getRight(), val, col));
else n.setColor(col);
if (isRed(n.getRight()) && !isRed(n.getLeft())) n = rotateLeft(n);
if (isRed(n.getLeft()) && isRed(n.getLeft().getLeft())) n = rotateRight(n);
if (isRed(n.getLeft()) && isRed(n.getRight())) flipColors(n);
return n;
}
However, the catch is that we are supposed to return a boolean value--if the user inserts a duplicate value as is already on the tree, we return false and don't attach the node. Otherwise, we attach them and return true; the code given to us for this is below, but is not recursive (part of the project requirements). And while I hadn't implemented a way of balancing or rotating properly, the returned boolean part works.
public boolean insertNode(Node node) {
//Here is just an example of setting colors for a node. So far, it is in green color. But you need to modify the code to dynamically adjust the color to
//either RED or BLACK according to the red-black logic
Node current_node;
// if the root exists
if (root == null) {
root = node; // let the root point to the current node
root.setColor(Node.BLACK);
return true;
} else {
current_node = root;
node.setColor(1);
while (current_node != null) {
int value = current_node.getValue();
if (node.getValue() < value){ // go to the left sub-tree
if (current_node.getLeft() != null) // if the left node is not empty
current_node = current_node.getLeft();
else{ // put node as the left child of current_node
current_node.setLeft(node);
node.setParent(current_node);
current_node = null; }
//System.out.println("Left:"+current_node);
}
else if (node.getValue() > value){ // go to the right
if (current_node.getRight() != null) // if the right node is not empty
current_node = current_node.getRight();
else{ // put node as the right child of current_node
current_node.setRight(node);
node.setParent(current_node);
current_node = null; }
//System.out.println("Right: "+current_node);
}
else{
//System.out.println("Else: "+current_node);
return false; }
//if(current_node!=null&&current_node.getLeft()!=null&&current_node.getRight()!=null&&current_node.getLeft().isRed()&&current_node.getRight().isRed())
// flipColors(node);
}
}
if(node.getParent()!=null){
node=node.getParent();
System.out.println("Case: node has parent, val="+node.getValue());
}
if(node.getLeft()!=null&&node.getRight()!=null){
if((node.getRight().isRed())&&!node.getLeft().isRed())
node=rotateLeft(node);
if((node.getLeft().isRed())&&(node.getParent()!=null)&&(node.getParent().getLeft().getLeft()!=null)&&(node.getParent().getLeft().getLeft().isRed()))
node=rotateRight(node);
if((node.getLeft().isRed()) && (node.getRight().isRed()))
flipColors(node);
}
return true;
}
I wasn't able to find any comparable implementations online, and it seems that the boolean is necessary for the program's gui to work properly. If someone has a good suggestion for where to start, I would appreciate it!
For the recursive insertNode, I would suggest you the following: Create a function insertNode(Node node, Node current_node) which returns a boolean value. The idea is to always call the function insertNode for the currently investigated node, starting from the root node. If the node cannot be immediately added to current_node, the responsible node is called recursively to handle the node. I have provided you a short example based on your code (with some comments what the basic idea is, there is obviously some stuff missing). I hope, I got your question correctly and this helps you with your understanding.
public boolean insertNode(Node node) {
if (root == null) {
root = node;
root.setColor(Node.BLACK);
return true;
} else {
boolean result = insertNode(node, root);
if (result) {
//Some other important stuff to do...
}
return result;
}
}
public boolean insertNode(Node node, Node current_node) {
int value = current_node.getValue();
if (node.getValue() < value) {
if (current_node.getLeft() != null) {
// Investigate left
return insertNode(node, current_node.getLeft());
} else {
// Insert node left
return true;
}
} else if (node.getValue() > value) {
if (current_node.getRight() != null) {
// Investigate right
return insertNode(node, current_node.getRight());
} else {
// Insert node right
return true;
}
} else {
return false;
}
}
I now have the working functions, as below:
public boolean insertNode(Node node) {
if(root==null){
root=node;
root.setColor(Node.BLACK);
return true;
}
else
node.setColor(Node.RED);
return insertNode(node, root);
}
public boolean insertNode(Node node, Node cur){
if(node.getValue()<cur.getValue()){
if(cur.getLeft()!=null)
return insertNode(node, cur.getLeft());
else{
cur.setLeft(node);
node.setParent(cur);
handleInsertion(node);
return true; } }
else if(node.getValue()>cur.getValue()){
if(cur.getRight()!=null)
return insertNode(node, cur.getRight());
else{
cur.setRight(node);
node.setParent(cur);
handleInsertion(node);
return true; } }
else
return false;
}

Not sure how to implement methods for Sorted List Java

EDIT 3: In short, what I'm asking is how can I fix the code I've written to do what the instructions for the assignment is asking(below each of the 4 blocks of code). I'm not sure what needs to be fixed to make it do what the instructions says.
I'm trying to figure out how to implement a few methods for an assignment I'm doing, but I can't seem to figure it out. The code below is what I have so far.
The first method is:
public boolean contains(int ID)
{
// TODO: implement this method
PersonNode current = m_first;
PersonNode previous = null;
if(current == null)
{
return false;
}
while(current != null)
{
if(current.getID() == ID)
{
return true;
//previous = current;
//current = current.getLink();
}
previous = current;
current = current.getLink();
}
return false; // replace this statement with your own return
}
This is what I have so far and I'm not sure if that's how it's supposed to be.
Instructions from assignment: This method takes an ID and checks whether a PersonNode associated with the given ID is in the list. If so, return true, otherwise, return false.
The second method is:
public PersonNode get(int ID)
{
// TODO: implement this method
PersonNode current = m_first;
PersonNode previous = null;
if(current == null)
{
return null;
}
while(current != null)
{
if(current.getID() == ID)
{
return current.getLink();
//previous = current;
//current = current.getLink();
}
previous = current;
current = current.getLink();
}
return null;
}
Instructions for this method: This method takes an ID and checks whether a PersonNode associated with the given ID is in the list. If so, return the reference to the node, otherwise, return null.
The third method is:
public boolean add(int ID, String name)
{
// TODO: implement this method
PersonNode newNode = new PersonNode(ID, name);
PersonNode current = m_first;
PersonNode previous = null;
if(m_first == null)
{
m_first = newNode;
m_numElements++;
return true;
}
while(current != null)
{
if(current.getName().compareToIgnoreCase(previous.getName()) <
previous.getName().compareToIgnoreCase(current.getName())) //not sure, fix
{
previous = current;
current = current.getLink();
}
else
{
break; //might be return false;
}
}
if(previous == null)
{
newNode.setLink(m_first);
m_first = newNode;
}
else
{
newNode.setLink(current);
previous.setLink(newNode);
}
return false; // replace this statement with your own return
}
The instructions for this method is: This method takes an ID and a name and adds a PersonNode with these values into the list. The list must still be sorted in ascending order by ID numbers. If add is successful, return true. If the node already exists in the list, return false.
The last method is:
public boolean remove(int ID)
{
// TODO: implement this method
PersonNode current = m_first;
PersonNode previous = null;
boolean found = false;
while(current != null)
{
if(current.getID() < ID)
{
previous = current;
current = current.getLink();
}
else if(current.getID() == ID)
{
found = true;
current = current.getLink();
if(previous == null)
{
m_first = current;
}
else
{
previous.setLink(current);
}
}
else
{
return found;
}
}
return false; // replace this statement with your own return
}
The instructions for this method: This method takes an ID and remove a PersonNode associated with the given ID from the list. If remove is successful, return true. If no such node exists, return false.
So that's what I have so far and I'm not sure if I'm on the right track or if I'm totally off.
Summary of what I need help with:
-Help implementing the methods. You don't have to give the code(I'd prefer if you don't, but the choice is yours), but if you do, keep it simple so I won't have to ask about it. I just need some guidance. Any help would be appreciated.
Additional info:
-Not allowed to implement additional methods or create variables that exist outside of those four methods.
-There's a PersonNode class and a Test Class(not posting the code for this since it's long, but if the methods are implemented correctly, it will work.)
Code for the PersonNode class:
public class PersonNode
{
private int m_ID;
private String m_name;
private PersonNode m_link;
public PersonNode(int ID, String name)
{
m_ID = ID;
m_name = name;
m_link = null;
}
public void setID(int ID)
{
m_ID = ID;
}
public int getID()
{
return m_ID;
}
public String getName()
{
return m_name;
}
public void setName(String name)
{
m_name = name;
}
public void setLink(PersonNode link)
{
m_link = link;
}
public PersonNode getLink()
{
return m_link;
}
}
If you can find other questions on SO that might help, feel free to link, but make sure you read my post first, don't just link anything related to sorted lists. I already tried looking, but the ones I found were not that helpful for my case.
If anything is not clear, I'll edit to make clearer. Sorry if the post is really long.
Edit: What I'm asking is how can I make the methods do what the instructions I posted below each one says. I'm not quite sure if my code is close to the instructions or not. The output gives incorrect results, most likely due to the implementation being incorrect.
EDIT 2: Updated contains() and get() with my new code. It's working a little more smoothly than before, but could still use some improvement. Also, add() and remove() still need work. Just look at the paragraph after each block of code for what I need help with. I'll be checking frequently, so feel free to lend a hand.
First, in your get() function, you need to return the PersonNode where the ID is match. So you should return current instead of return current.getLink(), which current.getLink() seems the next node of the linked list.
Second, your add() function seems not doing right. Since your list should always be sorted, you can iterate it from head until you find the ID is greater than input ID, that's the position you should insert your newNode.
PersonNode newNode = new PersonNode(ID, name);
PersonNode currentNode = mFirst;
for(; currentNode.getLink().getID() < ID; currentNode = currentNode.getLink());
newNode.setLink(currentNode.getLink());
currentNode.setLink(newNode);
However, you should consider some conditions which may cause this code fail:
The list is empty
If the list is empty, your mFirst will be null. Therefore, when you call currentNode.getLink() it will cause a NullPointerException. So you should add some check on it.
// insert when list is empty
if (mFirst == null) {
mFirst = newNode;
return true;
}
Insert at first position
If your new ID is smaller than all elements in the list, it will cause the code insert at the second position, not the first position. So you can add a test before get into the loop.
if (mFirst.getID() > ID) {
// insert at front
newNode.setLink(mFirst);
mFirst = newNode;
}
Insert at the last position
If your new ID is greater than all elements in the list, then your for loop will encounter a NullPointerException. When your currentNode is the last element in your list, currentNode.getLink() will return null, and at next step when you call currentNode.getLink() it will cause the exception. Therefore, you need to check this in the for loop (I replace it with a while loop).
while(true) {
if (currentNode.getID() == ID) {
// ID exists
return false;
}
PersonNode nextNode = currentNode.getLink();
if (nextNode == null) {
// insert at last
currentNode.setLink(newNode);
return true;
}
if (nextNode.getID() > ID) {
// insert at mid
newNode.setLink(nextNode);
currentNode.setLink(newNode);
return true;
}
currentNode = nextNode;
}
So finally, your add() function will looks like:
PersonNode newNode = new PersonNode(ID, name);
PersonNode currentNode = mFirst;
// insert when list is empty
if (mFirst == null) {
mFirst = newNode;
return true;
}
if (mFirst.getID() > ID) {
// insert at front
newNode.setLink(mFirst);
mFirst = newNode;
}
while(true) {
if (currentNode.getID() == ID) {
// ID exists
return false;
}
PersonNode nextNode = currentNode.getLink();
if (nextNode == null) {
// insert at last
currentNode.setLink(newNode);
return true;
}
if (nextNode.getID() > ID) {
// insert at mid
newNode.setLink(nextNode);
currentNode.setLink(newNode);
return true;
}
currentNode = nextNode;
}
Third, is your remove() function. Just go through the list and search for the specific ID. If found, link previous node to next node. It's very similar to the add() function.
// remove when the list is empty
if (mFirst == null) {
return false;
}
// remove at first
if (mFirst.getID() == ID) {
mFirst = mFirst.getLink();
return true;
}
PersonNode currentNode = mFirst,getLink();
PersonNode previousNode = mFirst;
while(true) {
if (currentNode == null) {
// ID not found
return false;
}
if (currentNode.getID() == ID) {
previouseNode.setLink(currentNode.getLinke());
return true;
}
currentNode = currentNode.getLink();
}
When implementing the LinkedList structure, remember to consider the conditions that may make your code fail and beware of the order of the instructions.
I think your while loop is not end ,and other problem i don't find.
while(current != null)
{
if(current.getID() == ID)
{
return true;
}
}//how the while out?

ArrayList .contains() sometimes true, sometimes false

I´m writing a simple Program which simulates a graph. This is how i implement a vertex: ( i used the word nodes for neighbours, thats a little confusing maybe..)
public class Vertex {
private String name;
private int nodes;
public Vertex(String name) {
this.name = name;
nodes = 0;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Vertex other = (Vertex) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equalsIgnoreCase(other.name))
return false;
return true;
}
In my Graph class I wrote a method which returns the neighbours(nodes) of a specific vertex:
public List<Vertex> getNodesOf(Vertex v) {
List<Vertex> nodes = new ArrayList<>();
if (vertices.contains(v)) { //vertices is an ArrayList<Vertex>
// adds all neighbours to nodes...
return nodes;
} else {
Terminal.printLine("Error, " + v.getName() + " does not exist here!");
return nodes;
When I call that method from my main method, it works fine:
List<Vertex> nodes = g.getNodesOf(new Vertex(input[1])); //input[1] is a name typed by the user
if (nodes != null) {
for (Vertex node : nodes) {
System.out.println(node.getName());
}
}
But I have another class for the dijkstra-algorithm to find the shortest path. this algorithm also needs the neighbours. this is a part of the code:
Vertex nearest = null;
int distanceInt = 9999;
for (Vertex vertex : unvisited) {
if (distance.containsKey(vertex)) {
if (distance.get(vertex) <= distanceInt) {
nearest = vertex;
distanceInt = distance.get(vertex);
}
}
}
if (graph.getNodesOf(nearest).contains(vertex)) {
// do something...
}
But when i call the method from here, it always says that the ArrayList doesn´t contain the Vertex and the //do something... will never be reached.
I overrided the equals and hashcode method with eclipse, so i thought, this was not the problem.
What´s my mistake?
Your equals()-hashCode()-implementation is broken. The spec says that equal objects must have equal hash-codes. But in your equals()-method you ignore the case of names while the hash-method does not ignore it.
This behaviour is relevant if you use hash-based maps, and distance.containsKey(vertex) looks like a typical map-lookup so I assume that your distance-object is a kind of Map.
Solution: Make your hashCode()-method also case-insensitive, or make your equals()-method case-sensitive.

recursive binary search tree remove method

First off, this is homework, so putting that out there.
I'm supposed to implement a binary search tree with specific methods:
void insert(String), boolean remove(String), and boolean find (String).
I have been able to successfully program and test the insert and find methods but am having difficulty with the remove.
What is going on in my program is the remove isn't actually removing anything from the tree and I believe this is because its only referencing the local creation of the current node but I could be wrong. I think I can implement the logic of the different cases I need to test (might need help with the deleting a node with two children case but I think I get it conceptually) am mainly trying to understand what I need to do differently to reference the tree properly in the
current = null; // case
Here is what I got so far:
public boolean remove(String title)
{
return remove(root, title);
}
private boolean remove(BSTNode current, String title)
{
if (current == null)
{
return false;
}
if (current.data == title)
{
if (current.left_child !=null && current.right_child != null)
{
return true; // returning true since I haven't finished writing this case
}
else if (current.left_child == null && current.right_child == null)
{
current = null; // this should remove the node from tree but it doesn't
return true;
}
else if (current.left_child != null && current.right_child == null)
{
current = current.left_child; // don't think this is right
return true;
}
else if (current.right_child != null && current.left_child == null)
{
current = current.right_child; // not sure about this
return true;
}
}
root = current;
if (title.compareToIgnoreCase(current.data) == -1)
{
return remove(current.left_child, title);
}
else
{
return remove(current.right_child, title);
}
}
Any knowledge is much appreciated.
A node is referenced by it's parent (except for the root, that node is referenced by your BST itself). In order to remove a node from the tree, you need to set that reference in the parent node to null.
What you're trying to do now is something like:
Before:
parent.left ---> node <--- current
After setting current = null:
parent.left ---> node current ---> null
that is, current references null, but that does not change the parent (only that local variable).
In your remove method you need to pass the parent along as well (or handle both children in the call for the parent, whatever you like better).
By the way: never, ever compare strings with ==, see for instance this question.
How to find the node and it's parent without explicitly storing the parent in each node:
I would say it is simpler to do this in a loop, rather than with recursion, but both would work. In a loop:
BSTNode parent = null;
BSTNode current = root;
boolean found = false;
while (!found && current != null) {
int compare = title.compareToIgnoreCase(current.data);
if (compare == 0) {
found = true;
} else {
parent = current;
if (compare < 0) {
current = current.left;
} else {
current = current.right;
}
}
}
if (!found) {
// title was not found
} else if (parent == null) {
// found the root
} else {
// found another node
}
By recursion is annoying, because you want a method that returns both the node and it's parent. You will need some simple inner class to solve this:
private class NodeAndParent {
public BSTNode node;
public BSTNode parent;
public NodeAndParent(BSTNode node, BSTNode parent) {
this.node = node;
this.parent = parent;
}
}
private boolean find(String title, NodeAndParent current) {
if (current.node == null) {
return false; // not found
} else {
int compare = title.compareToIgnoreCase(current.node.data);
if (compare == 0) {
return true; // found
} else {
current.parent = current.node;
if (compare < 0) {
current.node = current.node.left;
} else {
current.node = current.node.right;
}
}
}
}
private boolean remove(String title) {
NodeAndParent nodeAndParent = new NodeAndParent(root, null);
boolean found = find(title, nodeAndParent);
if (!found) {
// title was not found
} else if (nodeAndParent.parent == null) {
// found the root
} else {
// found another node
}
}

Categories

Resources