So I have two implementation of a method that searches a custom linked list with name as input and either gets the mark associated with the name if the name is found or returns -1.
public int getMark (String name) {
Node p = head;
while ((p != null) && !(p.getName().equals(name)){
p = p.getNext();
}
if (p == null){
return - 1;
}
else
{
return p.getMark();
}
}
OR
public int getMark(String name){
Node p = head;
if(head == null)
{
return -1;
break;
}
while(p != null)
{
if(p.getName().equals(name)
{
return p.getMark();
}
else
{
return -1;
}
p = p.getNext();
}
}
They both do the job but I want to know which solution is better. I personally find the first solution confusing and not logically sound.
Your first code is not seems better as if any of your node may be null then it will return -1 and not check further,
Also your second logic is little bit complex it should be as below which can perform better.
public int getMark(String name){
Node p = head;
if(head == null)
{
return -1;
}
while(p != null)
{
if(p.getName().equals(name)
{
return p.getMark();
}
p = p.getNext();
}
return -1;
}
Your second version won't work unless the head contains the correct one and the first version seems a bit too much. Have a look at this: It's faster and (in my opinion) more readable
public int getMark (String name) {
Node p = head;
//Check if head is the correct one
if (name.equals(p.getName())){
return p.getMark();
}
while (hasNext(p)){
p = p.getNext();
if (name.equals(p.getName())){
return p.getMark();
}
}
//Ending up here means we didn't find it
return -1;
}
private boolean hasNext(Node p){
return p.getNext() != null;
}
Note that I'm assuming head and 'name' are not null, otherwise this won't work of course
This would be my approach as it's concise and readable (in my opinion). Pretty much a variation of your first implementation. Arguably you could return -1 if the head is null.
public int getMark(String name) {
Node p = head;
while (p != null && !p.getName().equals(name)) {
p = p.next;
}
return p != null ? p.getMark() : -1;
}
Related
I have to implement a custom Iterator for a Binary Tree, which "next method" is sorting the binary tree. I'm not allowed to use any java.util package, so I can't use a stack for that.
#Override
public T next() {
T result = node.data;
if (node.rightChild != null) {
node = smallest(node.rightChild);
} else {
node = node.parent;
}
return result;
}
private Nodes<T> smallest(Nodes<T> n) {
if (n.leftChild != null) {
return smallest(n.leftChild);
} else {
return n;
}
}
At the moment, he just Iterate until there is no more rightChild. Can you please help me, finishing the "next method"?
Thanks to all of you
After a lot of testing this is my solution, which is working fine. If somebody needs the full Code just ask
#Override
public T next() {
T result = node.data;
if (node.rightChild != null) {
node = smallest(node.rightChild);
} else {
while (node.parent != null && node != node.parent.leftChild){
node = node.parent;
}
node = node.parent;
}
return result;
}
private Nodes<T> smallest(Nodes<T> n) {
if (n.leftChild != null) {
return smallest(n.leftChild);
} else {
return n;
}
}
I have a binary search tree. I know how to search using the search property. But my task is to search the tree without using search property.(Say, search in binary tree) This is how I have to search.
1. If you find the value in the current node return it.
2. else search in right. If not found in right, then search in left
3. If not found in the whole tree return null.
This is what i tried.
public Node search(int val)
{
Node target = this;
if(target.getVal() == val)
return this;
else if(target.getRight() == null && target.getLeft() == null)
return null;
if(target.getRight() != null)
{
return target.getRight().search(id);
}
if(target.getLeft() != null)
{
return target.getLeft().search(id);
}
return null;
}
Problem with my code is, if right child exists and val is not found in right I'm getting null value. (Not searching in left). How to resolve this?
public Node search(int val)
{
Node target = this;
if(target.getVal() == val)
return this;
else if(target.getRight() == null && target.getLeft() == null)
return null;
if(target.getRight() != null)
{
return target.getRight().search(id); //here lies the problem
}
if(target.getLeft() != null)
{
return target.getLeft().search(id);
}
return null;
}
The problem in your code is that you are returning the result of search in right subtree of the node being searched.
Here's the updated code
public Node search(int val)
{
Node target = null;
if(this.getVal() == val)
{
return this;
}
else if(this.getRight() == null && this.getLeft() == null)
return target;
if(this.getRight() != null)
{
target = this.getRight().search(id);
}
if(target==null && this.getLeft() != null)
{
target = this.getLeft().search(id);
}
return target;
}
This is untested code, but I'd change your logic a bit:
public Node search(int val)
{
if(this.getVal() == val)
return this;
if (this.getRight() != null) {
Node right = this.getRight().search(id);
if (right != null)
return right;
}
if (this.getLeft() != null) {
Node left = this.getLeft().search(id);
if (left != null)
return left;
}
return null;
}
In your version you are returning a solution with the sole requirement that the node on the right or left is not null. You have to return a solution only if a solution is found.
I'm getting a Stack overflow error for the following method at the recursive call. I think I need to make it iterative in order for it to work. How would I write the following method iteratively?
Node myMethod(String foo, Node p) {
if(p == null) {
p = new Node(foo);
p.link = spot;
spot = p;
p.calc[bar] = 1;
return p;
} else if(foo.equals(p.origin)) {
p.calc[bar] = p.calc[bar] + 1;
return p;
} else {
while (p.next == null & foo.equals(p.origin)){
p = p.next;
}
p.next = myMethod(foo, p.next);
return p;
}
}
p is a Node class that has String foo, String origin, Node link, Node next, and int Array calc[]. bar is an int. spot is a random node.
This is what I have tried so far
Node myMethod(String foo, Node p) {
if(p == null) {
p = new Node(foo);
p.link = spot;
spot = p;
p.calc[bar] = 1;
return p;
} else if(foo.equals(p.origin)) {
p.calc[bar] = p.calc[bar] + 1;
return p;
} else {
while (p.next == null & foo.equals(p.origin)){
p = p.next;
}
//instead of doing recursion on: p.next = myMethod(foo, p.next);. I tried the following:
if (p.next == null){
p.next = new Node(foo);
p.next.link = spot;
spot = p.next;
p.next.calc[bar] = 1;
} else if (foo.equals(p.next.origin)){
p.next.calc[bar] = p.next.calc[bar] + 1;
} else {
while (p.next.next == null & foo.equals(p.next.origin)){
p.next = p.next.next;
}
}
}
return p;
}
Although your iterative-try probably could be written better, this is a good try. However, look here:
else {
while (p.next == null & foo.equals(p.origin)){ //HERE! Check the while argument.
p = p.next;
} //instead of doing recursion on: p.next = myMethod(foo, p.next);. I tried the following:
…
The while loop will stop if p.next is null or foo does not equal p.origin. Now the basic approach would be to serve three cases here:
what to do when p.next != null (first while condition)
what to do when !foo.equals(p.origin) (second while condition) //you did not write it.
what to do when p.next != null && !foo.equals(p.origin)
If your while conditions are correct (ones you want them to be), you need to serve all cases for which the while loop may have stopped and that should be end of your algorithm. If it is not, rethink your while loop condition.
I'm still not entirely shure what you are trying to do and this code looks like bad programming style but maybe it will do what you need.
Node myMethod(String foo, Node p) {
while(p != null) {
if(foo.equals(p.origin)) {
p.calc[bar] = p.calc[bar] + 1;
break;
}
p = p.next;
}
if(p == null) {
p = new Node(foo);
p.link = spot;
spot = p;
p.calc[bar] = 1;
}
return p;
}
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
}
}
I'm trying to write a method, which returns the parent node of a given node.
public BinarySearchTreeNode<T> getParent(BinarySearchTreeNode<T> e) {
if (e == null) {
return null;
}
BinarySearchTreeNode<T> current = this.root;
T eValue = e.getValue();
while (current != null) {
if (howManyChildren(current) == 0) {
return null;
} else if (eValue.equals(current.getLeft().getValue())
|| eValue.equals(current.getRight().getValue())) {
return current;
} else if (eValue.compareTo(current.getValue()) < 0) {
current = current.getLeft();
} else {
current = current.getRight();
}
}
return null;
}
However I receive NullPointerExceptions, when one or both of the children are null-nodes and equals tries to compare the value with null.
How do I go on to fix this? I'm still new to Java.
You really need to check that the children are not null before you call a method on them. In this case you call current.getLeft().getValue() but the left child might be null. If it's null you will get the NullPointerException.
The following is an example with checking to make sure they aren't null before calling the method. Caveat, I didn't check to see if the entire code was correct besides the NullPointerException.
public BinarySearchTreeNode<T> getParent(BinarySearchTreeNode<T> e) {
if (e == null) {
return null;
}
BinarySearchTreeNode<T> current = this.root;
T eValue = e.getValue();
while (current != null) {
if (howManyChildren(current) == 0) {
return null;
} else if ((current.getLeft()!=null && eValue.equals(current.getLeft().getValue()))
|| (current.getRight()!=null) && eValue.equals(current.getRight().getValue())) {
return current;
} else if (eValue.compareTo(current.getValue()) < 0) {
current = current.getLeft();
} else {
current = current.getRight();
}
}
return null;
}
With object variables, when the value is null there is no object there that can supply the methods you would be calling.
You compare an object variable's value to null with:
if (obj == null) {
... do whatever ...
}
You can compare an object to null in many cases like this:
if (obj.equals(null)) ...
or
String s = null;
if (obj.equals(s)) ... this works
if (s.equals(obj)) ... this doesn't work
Note
In your code, if the node you are searching for is the root, it will never find it.
Similarly, you check all the children to see if they match and then you decide which of the children could match by comparing the value to the parent. Maybe you should reorder things a bit so you test the current node
If it's null, the search has ended in failure
If it matches, return its parent which you saved on the last iteration.
If it doesn't match, get the correct child -- right or left -- based on the value and loop.
This has the advantage that you only get the value of nodes when you know they aren't null.
T eValue = e.getValue();
BinarySearchTreeNode<T> prev = null;
BinarySearchTreeNode<T> current = this.root;
while (current != null) {
int compare = eValue.compareTo(current.getValue());
if (compare == 0) {
return prev;
}
prev = current; // save the parent in case it matches
if (compare < 0) {
current = current.getLeft();
} else {
current = current.getRight();
}
}