Whats wrong with my delete method in LinkedList (generic)? - java

I changed the LinkedList class, but it still does not work
LinearNode class
public class LinearNode<T>{
private LinearNode<T> next;
private T element;
public LinearNode()
{
next = null;
element = null;
}
public LinearNode (T elem)
{
next = null;
element = elem;
}
public LinearNode<T> getNext()
{
return next;
}
public void setNext (LinearNode<T> node)
{
next = node;
}
public T getElement()
{
return element;
}
public void setElement (T elem)
{
element = elem;
}
}
I can't figure out the problem with delete method in my java generic class
public void delete(T element){
LinearNode<T> previous = list;
LinearNode<T> current = list;
boolean found = false;
while (!found && current != null)
{
if (current.getElement ().equals (element)) {
found = true;
}
else {
previous = current;
current = current.getNext();
}
}
//found loop
if (found)//we fount the element
{
if(current == this.list){
previous.setNext (null);
this.last = previous;
}
else
if(current == this.last){
this.last.setNext(null);
this.last.equals(previous.getElement());
}
else{
previous.setNext(current.getNext());
current.setNext (null);
}
this.count--;
}
}
I have also my driver class which will delete the element from the linked list
also here the part of driver class
public void delete(){
Teacher aTeacher;
Scanner scan = new Scanner(System.in);
String number;
aTeacher = new Teacher();
System.out.println("Now you can delete teachers from the programme by their number.");
System.out.println("Please input number:");
number = scan.nextLine();
if (aTeacher.getNumber().equals(number)){
teachers.delete(aTeacher);
}
else {
System.out.println("There are no any teacher with this number.");
}
}

I can see a few problems in your code.
This loop is a little odd
while (current != null && !current.getElement().equals(element))
{
previous = current;
current = current.getNext();
found = true;
}
You shouldn't be setting found = true inside the loop on every iteration, because then you will always believe that you found the element after the loop is done. If you pass in values that you know exist in the list, then you wouldn't notice a problem. If you pass in values that are not in the list, then you will likely see current set to null later in your code.
I might write this instead
while (! found && current != null)
{
if (current.getElement ().equals (element)) {
found = true;
}
else {
previous = current;
current = current.getNext();
}
}
This block is a little odd too
if(current == this.last){
this.last.setNext(null);
this.last.equals(previous.getElement());
}
Neither of these statements seem like they would have any effect. The value of last.getNext () should already be null. this.last.equals(previous.getElement()) is merely testing whether the last node is equal to the element held in the next to last node; that evaluation should always be false and hopefully has no side-effects.
I might write this instead
if(current == this.last){
previous.setNext (null);
this.last = previous;
}
Finally, though it's not a problem for the delete per se, I would still be thorough here and make sure that the node being removed doesn't retain any references into the list.
So this
previous.setNext(current.getNext());
might become this
previous.setNext(current.getNext());
current.setNext (null);

Related

remove function in my linked list not working

I am supposed to build a method that will remove the first instance of a given value in a singly-linked list. However, whenever I try to test this method it will get stuck and I have to force the code to terminate.
edit: following advice, I have made a modified version method Contains that now works well and eliminates pointless repetition of Contains. so happily now the code works as it should!
Here is my code for the method:
public boolean remove(Anything m) {
//INCOMPLETE
if (this.first==null) {
System.out.println("there are no values in the list");
return false;
}
boolean returnValue;
returnValue=false;
if (this.contains(m)==true) {
Node temp=first;
while(temp.next!=null) {
if (temp.next.data==m) {
temp=temp.next.next;
temp.next=null;
returnValue=true;
}
else
returnValue=false;
}
}
return returnValue;
}
Here is my code for testing the method:
list13.addFirst("node5"); list13.addFirst("node4"); list13.addFirst("node3"); list13.addFirst("node2"); list13.addFirst("node1");
System.out.println("5-element list: " + list13);
System.out.println("Testing remove...");
System.out.println(list13.remove("node3"));
and just in case, here is the prebuilt code my assignment came with, if needed:
public class CS2LinkedList<Anything>
{
// the Node class is a private inner class used (only) by the LinkedList class
private class Node
{
private Anything data;
private Node next;
public Node(Anything a, Node n)
{
data = a;
next = n;
}
}
private Node first;
private Node last;
public CS2LinkedList()
{
first = null;
}
public boolean isEmpty()
{
return (first == null);
}
public void addFirst(Anything d)
{
Node temp = first;
first = new Node(d,temp);
}
public void clear()
{
first = null;
}
public boolean contains(Anything value)
{
for (Node curr = first; curr != null; curr = curr.next)
{
if (value.equals(curr.data)) {
return true;
}
}
return false;
}
public String toString()
{
StringBuilder result = new StringBuilder(); //String result = "";
for (Node curr = first; curr != null; curr = curr.next)
result.append(curr.data + "->"); //result = result + curr.data + "->";
result.append("[null]");
return result.toString(); //return result + "[null]";
}
```
Some issues:
At a match, you are reassigning to temp the node that follows after the node to be deleted, and then you clear temp.next. That is breaking the list after the node to be deleted.
The while loop does not change the value of temp when the if condition is not true. So the loop can hang.
You can stop the search when you have identified the node to delete. By consequence you don't need the else inside the while loop.
while(temp.next!=null) {
if (temp.next.data==m) {
// skip the node by modifying `temp.next`:
temp.next = temp.next.next;
returnValue=true;
break; // we removed the targeted node, so get out
}
temp = temp.next; // must move to next node in the list
}
It is a pity that you first iterate the list with this.contains(m), only to iterate it again to find the same node again. I would just remove that if line, and execute the loop that follows any way: it will detect whether the list contains the value or not.
Be aware that your function has no provision for removing the first node of the list. It starts comparing after the first node. You may want to cover this boundary case.

JAVA: My Linkedlist is only printing my head element and nothing else

I have written my own linked list and am reading integers from a file into the list and printing them out. However, only the head of my list is printing and nothing else. I've been staring at this code for so long I feel insane, can anyone help?
Method in a separate 'files' class that reads in a file of integers separated by whitespace. This method will take the next integer and add it to my linked list.
public void readValues() {
LinkedList list = new LinkedList();
while(scan.hasNextInt()) {
Integer someData = scan.nextInt();
list.addNode(someData);
}
list.printList();
}
This method is in my LinkedList class which takes the data sent from my readValues method in my files class.
public void addNode(Integer someData) {
myNode = new LinkedNode(someData,null);
//initialize node if this is first element
if (head == null) {
head = myNode;
size++;
}
else if (myNode.getNext() == null) {
myNode.setNext(myNode);
size ++;
}
else if (myNode.getNext() != null) {
while(myNode.getNext() != null) {
myNode = myNode.getNext();
}
myNode.setNext(myNode);
size++;
}
}
This method is also in my LinkedList class and successfully prints the head of my list which with my data is the number 40 followed by ---> and then nothing else. It should print ever other integer read in from my file.
public void printList() {
LinkedNode current = head;
if (head == null) {
System.out.print("list is empty");
return;
}
while(current != null) {
System.out.print(current.getElement());
System.out.print(" --> ");
current = current.getNext();
}
}
LinkedNode class:
public class LinkedNode {
Integer data;
LinkedNode next;
public LinkedNode(Integer someData, LinkedNode next) {
this.data = someData;
this.next = null;
}
public int getElement() {
return data;
}
public void setElement(Integer data) {
this.data = data;
}
public LinkedNode getNext() {
return next;
}
public void setNext(LinkedNode next) {
this.next = next;
}
public String toString() {
return data + "";
}
}
Your code has a small bug in the if else conditions in your addNode() method due to which your data is not getting added in the list.
Root Cause
When you add a new node to your list,
In the first iteration
The head is currently null and hence the first if conditions becomes true and your first node gets added (That's why you got the data 40).
In the Subsequent iteration(s)
your else if condition checks the myNode's next pointer which will always be null (as per the constructor) and thus it's next pointer points towards itself. The nodes created from here do not become the part of the list as the next pointer of head was never assigned to any of these and these nodes also point to themselves only.
Solution
I made a little modification in the if else conditions:
public void addNode(Integer someData) {
LinkedNode myNode = new LinkedNode(someData,null);
//initialize node if this is first element
if (head == null) {
head = myNode;
size++;
}
else if (head.getNext() == null) {
head.setNext(myNode);
size ++;
}
else if (head.getNext() != null) {
System.out.println("in second else if");
LinkedNode n = head;
while(n.getNext() != null) {
n = n.getNext();
}
n.setNext(myNode);
size++;
}
}
PS: Try debugging your code with dry run, it's a great mental exercise and helps in boosting the learning curve significantly too. All the best! :)
The problem is with your addNode() method. Inside the addNode() method you are first creating a new node named mynode. Now when the head is null it sets head to mynode, thats ok. But when the head is not null the mynode is not being added to the list. Thats why only the first element exist and other's are getting lost.
Hope this helps. Let me know if I can help with anything else. Happy coding!

Java Iterator Not Working With Single Iterable Object

I am having a problem with Iterators. I am writing a custom linked list as using an iterator to be able to traverse the list.
The iterator looks like this:
public class NodeIterator implements Iterator<Node> {
private Node current = head;
private Node lastReturned = head;
public boolean hasNext() {
return lastReturned.getLink() != null;
}
public Node next() {
lastReturned = current;
current = current.getLink();
return lastReturned;
}
public void remove() {
removeNode(lastReturned);
lastReturned = null;
}
}
I'm still in the early stages so I'm testing the data structures from the console by populating the nodes with this method.
private static void MethodToPopulateNodes() {
MyObject o = new MyObject();
String[] responses = new String[prompts.length];
scanner = new Scanner(System.in);
boolean done = false;
String s = null;
while (!done) {
int i = 0;
for (String prompt : prompts) {
System.out.println(prompt);
s = scanner.nextLine();
if (s.equalsIgnoreCase("stop")) {
done = true;
break;
} else {
responses[i] = s;
}
i++;
}
if (done) {
break;
}
o = new MyObject(responses);
myNode.add(c);
}
}
When I try to use the iterator when there is only one Node, it doesn't do anything. No errors or anything. However, if I have multiple nodes, this foreach works flawlessly.
public static void main(String[] args) {
myNode = new Node();
methodToPopulateLinkedList();
for (Node node : myNode) {
//toString is overridden for my object
System.out.println(node.getData().toString());
}
}
UPDATE: I edited the iterator to return hasNext() == true on the first iteration:
public class NodeIterator implements Iterator<Node> {
private boolean done = false;
private Node current = head;
private Node lastReturned = head;
public boolean hasNext() {
if (head == tail && head != null && !done) {
done = true;
return true;
}
return lastReturned.getLink() != null;
}
public Node next() {
lastReturned = current;
current = current.getLink();
return lastReturned;
}
public void remove() {
removeNode(lastReturned);
lastReturned = null;
}
}
I feel like that is super janky but it works. It seems like Java calls hasNext() first before calling next so I have to treat the special case differently.
|123
hasNext() == true
next() == 1
1|23
hasNext() == true
next() == 2
12|3
Where | equals the cursor. Is that accurate? Is there a better way to solve this?
If there's just one Node, it would have the special case of its ->next being null. Before the loop, try printing out the first node, I think your loop might be looking one ahead.

How do I add objects into a linked list?

I have been working on a project where I must implement a java class that implements the use of doubly linked lists. I have the LinkedList class finished with all my methods. I'm just unsure how to actually add node objects into the list. Here is my code so far with test at the bottom. Any help would be appreciated. Thanks
public class LinkedList {
private Node first;
private Node current;
private Node last;
private int currentIndex;
private int numElements;
public LinkedList() {
this.first = null;
this.last = null;
this.numElements = 0;
this.current = null;
this.currentIndex = -1;
}
private class Node {
Node next;
Node previous;
Object data;
}
public boolean hasNext() {
return (current != null && current.next != null);
}
public Object next() {
if (!this.hasNext()) {
throw new IllegalStateException("No next");
}
current = current.next;
return current.data;
}
public boolean hasPrevious() {
return (current != null && current.previous != null);
}
public Object previous() {
if (!this.hasPrevious()) {
throw new IllegalStateException("No previous");
}
current = current.previous;
return current.data;
}
int nextIndex() {
int index = numElements;
if (hasNext()) {
index = this.currentIndex + 1;
}
System.out.println(index + "The current index is " + current);
return index;
}
int previousIndex() {
int index = -1;
if (hasPrevious()) {
index = this.currentIndex - 1;
}
System.out.println(index + "The current index is " + current);
return index;
}
public void set(Object o) {
if (this.current == null) {
throw new IllegalStateException("No node found, cannot set.");
}
current.data = o;
}
public int size() {
return numElements;
}
public void add(Object o) {
Node newNode = new Node();
newNode.data = o;
if (first == null) {
first = newNode;
last = newNode;
newNode.next = null;
} else if (first != null) {
if (current == null) {
newNode.previous = null;
newNode.next = first;
first.previous = newNode;
first = newNode;
} else if (current == last) {
newNode.previous = current;
newNode.next = null;
current.next = newNode;
last = newNode;
} else {
newNode.previous = current;
newNode.next = current.next;
current.next.previous = newNode;
current.next = newNode;
}
}
current = newNode;
numElements++;
currentIndex++;
}
public void remove() {
if (current != null) {
if (current == first && current == last) {
first = null;
last = null;
} else if (current == last) {
current.previous = null;
last = current.previous;
} else if (current == last) {
current.previous.next = null;
last = current.previous;
} else {
current.previous.next = current.next;
current.next.previous = current.previous;
}
current = current.next;
numElements--;
}
}
}
import java.util.Scanner;
public class LinkedListTest {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String name;
int index;
LinkedList<Object> listOne = new LinkedList<Object>();
listOne.add(object o);
}
}
The posted class LinkedList looks functional to me.
Make sure that your test code does not confuse this class and java.util.LinkedList, which Java provides for you (It's a part of the existing Collections framework).
For clarity, I would recommend renaming your class to something like MyLinkedList
The following code works and the output is "0","2":
public class MyLinkedListTest {
public static final void main(String[] args) {
MyLinkedList list = new MyLinkedList();
System.out.println("Number of items in the list: " + list.size());
String item1 = "foo";
String item2 = "bar";
list.add(item1);
list.add(item2);
System.out.println("Number of items in the list: " + list.size());
// and so on...
}
}
I'd be surprised if your code compiled, since your class isn't actually generic. Just initialize it as LinkedList listOne = new LinkedList(); (no angle brackets).
As to actually adding elements, you just need an instance of some Object to add; anything will do (assuming your internal code works properly). Try this down at the end there:
Object objectToAdd = "Strings are Objects";
listOne.add(objectToAdd);
objectToAdd = new File("C:\\foo.bar"); // Or use any other Objects!
listOne.add(objectToAdd);
Think of numbered list and look at the relations between the elements
Say I have the list:
A
B
C
What do I have to do to the relations get the list:
A
B
NewNode
C
The new next node of B is NewNode
The new previous node of C is NewNode. So an insert function would want to know the immediate previous node or the immediate next node and then adjust the relationships.
Your LinkedList doesn't have generic types so you can't declare it as
LinkedList<Object> listOne = new LinkedList<Object>();
but rather as
LinkedList listOne = new LinkedList();
And now to add elements just use your add method
listOne.add("something");
listOne.add(1);//int will be autoboxed to Integer objects
Also if you want to add data from keyboard you can use something like
String line="";
do{
System.out.println("type what you want to add to list:");
line = keyboard.nextLine();
listOne.add(line);
}while(!line.equals("exit"));
The line
LinkedList<Object> listOne = new LinkedList<Object>();
won't compile unless you change your class declaration to
class LinkedList<T>
or alternately you can just write
LinkedList listOne = new LinkedLis();
After that you should be able to add objects to your list. However, you'll need to create an Object to add to it, listOne.add(object o); won't do--at the very least you'll have to write listOne.add(new Object()). (Your code does not instantiate an Object, there is no Object that you already have called o, and besides, object o does not mean anything in Java and would not compile.
As people have mentioned your list is not generic. However as they advise you to get rid of the parameter, you can also just add <Object> or <E> to your linked list implementation and leave your initialization of the list as it is.
So in your linked list class you should do something like:
public class LinkedList<E>
This will make sure when you're using LinkedList<Object> listOne = new LinkedList<Object>();, E will be covnerted to Object
Let's improve your test a little bit so that it becomes apparent where your problems are (if any) I commented out the call to the current() method since you have not included one. (I would leave this alone as it may confuse you.) The general idea would be to add items to the linked list and walk forward and backward through it checking the items with each step.
public class LinkedListTest {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String name;
int index;
LinkedList listOne = new LinkedList();
//Initially we should be empty so we are positioned
// at both the beginning and end of the list
assert listOne.size() == 0 :"List should be empty";
assert listOne.hasPrevious()==false: "Should be at the beginning of the list";
assert listOne.hasNext()==false : "Should be at the end of the list";
Object firstNode = "I am the first node";
listOne.add(firstNode); //we've added something
//I left this commented out since you don't have a current() method.
// assert firstNode == listOne.current() : "Our current item should be what we just added";
assert listOne.hasPrevious()==false : "Should not have moved forward in our list yet";
assert listOne.hasNext()==true : "should have an item after our current";
assert listOne.size() == 1 : "Should only have one item in the list";
Object secondNode = "I am the second node";
listOne.add(secondNode);
assert listOne.size() == 2 : "Should only have two items in the list";
assert firstNode == listOne.next() : "1st call to next should return the 1st node";
assert listOne.hasPrevious()==true : "We should be positioned after the 1st node";
assert listOne.hasNext()==true : "We should be positioned before the 2nd node";
}
}

LinkedList - loop not working - Java

I am required to write a method that returns a number - the amount of times an element is found in a linked list. So far I have;
package Question4;
import net.datastructures.Node;
public class SLinkedListExtended<E> extends SLinkedList<E> {
// returns the number of occurrences of the given element in the list
public int count(E elem) {
Node<E> cursor = tail;
int counter = 0;
if ((cursor != null) && (!(cursor.getElement().equals(elem)))) { //tail isnt null and element is not equal to elem
cursor = cursor.getNext(); //go to next node
} else if ((cursor != null) && (cursor.getElement().equals(elem))){ //cursor isn't null and element equals elem
counter++; //increment counter
}
else {
return counter; //return counter
}
return counter;
}
public static void main(String[] args) {
SLinkedListExtended<String> x = new SLinkedListExtended<String>();
x.insertAtTail("abc");
x.insertAtTail("def");
x.insertAtTail("def");
x.insertAtTail("xyz");
System.out.println(x.count("def")); // should print "2"
x.insertAtTail(null);
x.insertAtTail("def");
x.insertAtTail(null);
System.out.println(x.count("def")); // should print "3"
System.out.println(x.count(null)); // should print "2"
}
}
I have extended to a class which compiles correctly, so I know the problem is in my method. I can't figure out what to do, my code returns 0, which is probably the counter integer remaining at 0 and not going through the loop statement. Any ideas are appreciated.
Edit. SLinkedList code:
import net.datastructures.Node;
public class SLinkedList<E> {
protected Node<E> head; // head node of the list
protected Node<E> tail; // tail node of the list (if needed)
protected long size; // number of nodes in the list (if needed)
// default constructor that creates an empty list
public SLinkedList() {
head = null;
tail = null;
size = 0;
}
// update and search methods
public void insertAtHead(E element) {
head = new Node<E>(element, head);
size++;
if (size == 1) {
tail = head;
}
}
public void insertAtTail(E element) {
Node<E> newNode = new Node<E>(element, null);
if (head != null) {
tail.setNext(newNode);
} else {
head = newNode;
}
tail = newNode;
size++;
}
public static void main(String[] args) { // test
SLinkedList<String> list = new SLinkedList<String>();
list.insertAtHead("lol");
}
}
Maybe you should use a while loop instead of an if clause
**while** ((cursor != null) && (!(cursor.getElement().equals(elem)))) {
The code in count is not in a loop, so it'll just return after the first element.
Try this:
public int count(E elem) {
Node<E> cursor = tail;
int counter = 0;
while (true)
{
if ((cursor != null) && (!(cursor.getElement().equals(elem)))) { //tail isnt null and element is not equal to elem
cursor = cursor.getNext(); //go to next node
} else if ((cursor != null) && (cursor.getElement().equals(elem))){ //cursor isn't null and element equals elem
counter++; //increment counter
}
else {
return counter; //return counter
}
}
}
Also, note that cursor.getElement().equals(elem) will return a NullPointerException when cursor.getElement() is null. The easiest way to deal with this is probably to write a separate equals method:
boolean equals(E e1, E e2)
{
if (e1 == null)
return e2 == null;
if (e2 == null)
return false;
return e1.equals(e2);
}
Also, presumably Node<E> cursor = tail; makes it point to the end of the list and presumably you want Node<E> cursor = head; instead.
One of the fundamental things that you were missing was a loop. Since you are essentially searching for something, you want to loop through the entire list. Once you run into an element that matches the one that you are searching for, you want to increment the count by 1. Once you have finished looping through the entire list, you want to return that count. So this is my solution. I keep it simple so you could understand:
import java.util.LinkedList;
public class Duplicates<E> extends LinkedList<E> {
public static void main(String[] args) {
Duplicates<String> duplicates = new Duplicates<String>();
duplicates.add("abc");
duplicates.add("def");
duplicates.add("def");
duplicates.add("xyz");
System.out.println(duplicates.duplicateCount("def"));
duplicates.add(null);
duplicates.add("def");
duplicates.add(null);
System.out.println(duplicates.duplicateCount("def"));
System.out.println(duplicates.duplicateCount(null));
}
public int duplicateCount(E element) {
int count = 0;
for (E e : this) {
if (e == element) {
count++;
}
}
return count;
}
}
Output:
2
3
2
I suggest you combine Martin's answer (which tells you how to count the elements) with this, which tell you how to be able to use foreach - you just have to make your SLinkedListExtended implement Iterable, whioch should be something liek the follwoing (you could do this on SLinkedList, but I'm assuming you were told not to alter the code for that one):
public class SLinkedListExtended<E> extends SLinkedList<E> implements Iterable<E> () {
public Iterator<E> iterator() {
final Node<E> itHead = head;
return new Iterator<E>() {
Node<E> current = itHead;
long position = 0;
public boolean hasNext() {
return current != null && position < size;
}
public E next() {
current = current.getNext();
++position;
return current.getElement();
}
public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
};
}
};
I can't vouch for all the details, but this should cover most of it. You may also consider using equals instead of ==, but don't forget to check the elements for nullity.
next should only be called if hasNext is true, so it's not a problem if it throws an exception (but it should be a NoSuchElementException to keep in line with the contract).
Implementing Iterable makes your class compatible with the Collections library, hence the support for foreach, but you can use it to do raw iteration by calling iterator, hasNext and next yourself.

Categories