I'm writing a LinkedList class for an assignment and I'm writing my insert method and was wondering if I could get it looked at.
private Node first; // start of the list
private class Node {
private Item item;
private Node next;
}
public boolean insert(Item item) {
// add item to list if it doesn't already exist
// return true if a new Node is created, otherwise false
if ( first.next == null && first.item == item) {
return false;
}
Node ptr = first;
while (ptr.next != null) {
if (ptr.item == item) {
return false;
}
ptr = ptr.next;
}
Node oldFirst = first;
first = new Node();
first.item = item;
first.next = oldFirst;
return true;
}
For the most part I think it's okay, but everytime I try to trace the insert method I end up confusing myself and messing up all the reference changes. Can someone tell me if I'm doing it right? Any other improvements would be appreciated too.
I would consider writing an extra function for checking if the Item is already in the list. This would make the insert function more clear and the whole reference changing would only be there. Also your first test:
if ( first.next == null && first.item == item) {
return false;
}
does nothing else then the first iteration of the while loop.
You should definitely initialize first so that you don't throw a NullPointerExcpetion as #threenplusone said or check if:first == null. (the first ptr.next in your while-loop throws a NPE if first is null)
Also you should compare your items by equals as #Thilo said.
The rest is correct I think.
Your insert method is not OO - you're using a while loop to traverse the list, so this method could be a static method (if you also passed in the first node).
A more elegant way would be:
In pseudo-code:
insert(item) {
if (next == null)
add item to "this" // we are at end of list
else
next.insert(item) // hand item to the next node
}
Related
I'm trying to find a specific node in a binary tree using Java. My method for finding the node returns the node that contains the data that was searched for.
My code looks like this:
public BinNode find(Comparable item) throws NullPointerException {
if (item == null) {
throw new NullPointerException("item is NULL");
} else if (root == null) {
throw new NullPointerException("tree is empty");
}
return find(root, item);
}
public static boolean found = false;
public BinNode find(BinNode k, Comparable item) throws NullPointerException {
if (k.getData().equals(item)) {
found = true;
return k;
}
if (!found && k.getChildLeft() != null) {
find(k.getChildLeft(), item);
}
if (!found && k.getChildRight() != null) {
find(k.getChildRight(), item);
}
return k;
}
Running the debugger I can see, that when I search for an item that exists in the tree, it will find the correct node and go to the first return statement after "found" is set to true.
However, then compiler doesn't return that Node to the method call, but goes on to the second return statement, returning the root. So no matter where the Node is located, the method will always return the root.
What am I doing wrong?
Your method never returns "not found" which is fundamentally wrong because most of the times an item is not in the data. And that is your main problem. You need to return null / an empty Optional in the bottom return statement. And then you need to properly handle that "not found" return value when traversing the tree downwards, namely where you call find for the left and right child.
Your logic has to always be:
has the current node the correct value
if yes return the current node
does the left node contain the value
if yes return the corresponding node from the left
does the right node contain the value
if yes return the corresponding node from the right
return "not found" (because the current node is not correct and neither the left nor the right contain the value)
You currently skip / have not implemented the two nested "if yes return the corresponding node from the left/right" code paths.
(and of course remove the found variable as noted in a comment)
public BinNode find(BinNode k, Comparable item) throws NullPointerException {
if (k.getData().equals(item)) {
return k;
}
if (k.getChildLeft() != null) {
BinNode node = find(k.getChildLeft(), item);
if (node != null) return node;
}
if (k.getChildRight() != null) {
BinNode node = find(k.getChildRight(), item);
if (node != null) return node;
}
return null;
}
You need to return the finds from the left and right calls.
Your code finds the node and returns the k, but the other finds make no returns so your code continues on with code after the conditional statements, which is to return the node k. However, this falls back through the return stack to the original call to the double argument find, which has root as the BinNode given, so that is what is returned.
Refer Luk2302 answer.
You forgot "return" for left and right calls for find() function.
if (!found && k.getChildLeft() != null) {
return find(k.getChildLeft(), item);
}
if (!found && k.getChildRight() != null) {
return find(k.getChildRight(), item);
}
I am having a lot of difficulty figuring out the add method of a linked list. My assignment says to:
Implement this method, public void add(E item), inside MoveToFront
class. The method behaves like this: when the input does not exist in
the linked list, add it at the front; otherwise remove the existing
one from the list and reinsert it to the front.
What I have done so far is create a contains and delete method that will search for the existing item in the list and then delete it. Then it will add the item to the front of the list.
public int getLength() {
Node<E> curNode = first;
int count = 0;
while (curNode != null) {
curNode = curNode.next;
count++;
}
return count;
}
public boolean Contains(E item) {
if (first == null) {
return false;
}
Node<E> currentNode = first;
while (currentNode.next != null) {
containCount++;
if (currentNode.item.equals(item)) {
return true;
}
currentNode = currentNode.next;
}
return false;
}
public E Delete(int kth) {
if (kth <= getLength()) {
Node<E> currentNode = first;
for (int i = 1; i < kth; i++) {
currentNode = currentNode.next;
}
currentNode.next = currentNode.next.next;
return currentNode.item;
} else {
return null;
}
}
public void add(E item) {
if (!Contains(item)) {
Node<E> myNode = new Node<E>(item, null);
first = myNode;
} else {
Delete(containCount);
Node<E> myNode = new Node<E>(item, null);
first = myNode;
}
}
I think you aren't properly linking the nodes. Before you set the node you're inserting as the first node, set the node's next to the old first, like this:
myNode.next = first;
first = myNode;
A couple of things:
Instead of going through the list twice to first check if it contains the item, then to find and delete it, you can rewrite delete() to just go through the list and delete if a matching item is found. You can then call this method at the beginning of your add() method.
You should keep track of the size of the list with a simple instance variable that is updated whenever an item is added or removed, and then just let getLength() return this. Going through the whole list each time is way too expensive.
First of all I see a getLength() method in your code. It is a linked list, if you are trying to get the length of it for this problem then you didn't get the data structure.
Now if we get to implementation I see from the requirement you have to add new element to the front one way or another. This is how I will do that-
Create a node and link its next to the first element of current list. This will be add method.you can do this method in the end too, it will not make much difference.
Then start searching for element in the list and if you find a match delete it. Make sure you don't match with the element you just added int the front.
I'm implementing a deque using singly linked list in Java. My addFirst() function is working fine, but addLast() is not working.
Whenever I call addLast(), I got the following error message:
java.lang.NullPointerException
Your last is null at first.
When you assign it to old_last, old_last is null too.
So when you call old_last.next, NPE will throw.
Giving your Node class a constructor will help to keep your code short and DRY:
private class Node {
Item item;
Node next;
private Node(Item item, Node next) {
if (item == null) throw new NullPointerException();
// 'this' refers to the created instance and helps distinguish the field from the param
this.item = item;
this.next = next;
}
}
public void addFirst(Item item) {
// creates a new Node before first so to speak and then repoints first to this node
first = new Node(item, first);
if (num_elements==0) last = first;
num_elements++;
}
public void addLast(Item item) {
if (num_elements == 0) {
// this will deal with the case (last==null) which causes the NPE
addFirst(item);
return;
}
last.next = new Node(item, null);
last = last.next;
num_elements++;
}
That aside, a singly linked list is not the ideal data structure for a deque. While adding is O(1) on both ends, removing from the back would be O(N)!
I need to make a method that removes the last element of a LinkedList using recursion.
This is what I have so far but it doesn't seem to be removing the node...when i call list.size() it is still the same size with the same values. What am I doing wrong here?
This is for Java by the way
public void removeLastElement(Node curr){
if (curr == null)
return;
else{
if(curr.next == null)
curr = null;
else
removeLastElement(curr.next);
}
}
In a LinkedList to remove the last element you have to get the penultimate element and set
curr.next = null
You're in the right way to get the recurrent function to remove the last node. The problem is you're identifying the penultimate node with curr.next == null, if you got it, you nullify it, but that's your actual input! So, you must check if the actual node is the antepenultimate node on the list:
if (curr.next.next == null) {
curr.next = null; //Now you're modifying the data in your input.
}
With this change, there are more basic cases to check, but that's up to you, my friend.
Boolean deleteLast(Node n)
{
if(n.next == null)
return true;
if(deleteLast(n.next))
{
n.next = null;
return false;
}
return false;
}
Node deleteLast(Node n) {
if (n.next == null)
return null;
n.next = deleteLast(n.next);
return this;
}
The general idea is you ask the next node "hey, can you tell me where you are, and delete your last node?" The last node can then just say "I'm nowhere" and it'll all fall into place.
This is very similar to Aadi's answer, just using Nodes instead of booleans.
I am trying to make an add method for a linked list, but for some reason (that is not obvious to me, in fact I came here to get help finding the error) it goes into an infinite loop every time.
EDIT: I found the error, and I will keep my original code with a comment with the corrected code
public void insert(String majorName)
{
MajorNode newNode = new MajorNode(majorName, 1);
boolean inList = false;
MajorNode current = first;
if(isEmpty())
{
first = newNode;
// inList = true;
}
else
{
while(current.next != null)
{
if(current.majorName.equalsIgnoreCase(majorName))
{
current.frequency++;
inList = true;
break;
}
else
{
current = current.next;
}
}
}
if(!inList)
{
newNode.next = first;
first = newNode;
}
}
Here is my node class if it is needed:
public class MajorNode
{
public String majorName;
public int frequency;
public MajorNode next;
public MajorNode(String majorName, int frequency)
{
this.majorName = majorName;
this.frequency = frequency;
}
public String toString()
{
return majorName + " " + frequency;
}
}
On the first call to insert(), one assumes isEmpty() returns true and consequently first is set to the newNode before newNode's next field is set to the previous (null) value of first. Thus, when the list is non-empty, the loop iterates indefinitely on the last element in the list whose next field points to itself.
Out of curiosity, why are you trying to implement your own linked list functionality rather than build upon available packages (such as java.util.LinkedList<E>)?
When you create the first node you do this:
if(!inList)
{
newNode.next = first;
first = newNode;
}
This points the first nodes next at itself... hence a loop
You should be leaving the newNode.next as null for the first node, so that when you insert the second item, you reach the end of the chain..
You will have an wrong frequency if you add a node which is similar to the last node of your List. Consider this situation (adding 2 similar nodes in the empty list)
You will add a node1 in a blank list. So first & current will point to node1. (but node1.next will be null)
If you add the same node (or a node with a same majorName), you will reach to while loop (because List is not empty now). And also, you will not enter into a while loop as well. (as your current.next is still null)
and you will end up with two noes with same majorName in your list.
I would suggest to use
while(current != null)
instead of
while(current.next != null)