Remove all occurrences of item from a Linked List - java

I've been working on this lab assignment for a few hours and can't understand why this code is not working. The question is to add the method int removeEvery(T item) that removes all occurrences of item and returns the number of removed items to a link list class that implements a link list interface.
This is my code: It removes some occurrences of the item, but not all of them.
public int removeEvery(T item){
int index = 0;
Node currentNode = firstNode;
for(int i = 1; i <= numberOfEntries; i++)
{
System.out.println(currentNode.getData());
if (item.equals(currentNode.getData())){
index++;
remove(i);}
else{
currentNode = currentNode.getNextNode();}
}
if(index != 0)
return index;
return -1;
}
Here is the remove method that was included in the LinkList class:
public T remove(int givenPosition)
{
T result = null; // return value
if ((givenPosition >= 1) && (givenPosition <= numberOfEntries))
{
assert !isEmpty();
if (givenPosition == 1) // case 1: remove first entry
{
result = firstNode.getData(); // save entry to be removed
firstNode = firstNode.getNextNode();
if (numberOfEntries == 1)
lastNode = null; // solitary entry was removed
}
else // case 2: givenPosition > 1
{
Node nodeBefore = getNodeAt(givenPosition - 1);
Node nodeToRemove = nodeBefore.getNextNode();
Node nodeAfter = nodeToRemove.getNextNode();
nodeBefore.setNextNode(nodeAfter); // disconnect the node to be removed
result = nodeToRemove.getData(); // save entry to be removed
if (givenPosition == numberOfEntries)
lastNode = nodeBefore; // last node was removed
} // end if
numberOfEntries--;
} // end if
return result; // return removed entry, or
// null if operation fails
} // end remove

There is something special with your linked list, you can access next element with current.getNextNode but you delete using the element index. You should look in the rest of your implementation how this index is managed. Does the first element have index 0 or 1 (you start your loop with 1). What happens to the indexes of all elements when you remove one. Do the elements know their index ?
You could use something like
int deletedNodes = 0;
int currentIndex = 0; // check if 1 or 0
currentNode = fist;
while(currentNode != null){ // I guess lastNode.getNextNode() is null
if(//should remove){
remove(currentIndex);
deletedNodes++
// probably no need to change the index as all element should have been shifted back one index
} else {
currentIndex++; // index changes only if no node was deleted
}
currentNode = currentNode.getNextNode(); // will work even if it was deleted
}
return deletedNodes;

I think the problem you have comes from remove(i).
When you remove the i-th element, the i+1-th element becomes the i-th and so on: every element is shifted. Therefore if you need to remove 2 elements in your list that are at index j and j+1, removing the j-th element calling remove(j) will shift the j+1-th element at the index j. Hence removing that second element requires calling remove(j) again, and not remove(j+1).
So you need to decrement i after removing.
Since your remove method actually decrements numberOfEntries, the condition on your while loop is properly updated. So all you need to do is replace
if (item.equals(currentNode.getData())) {
index++;
remove(i);
}
else {
currentNode = currentNode.getNextNode();
}
by
if (item.equals(currentNode.getData())) {
index++;
remove(i--);
}
// update the current node, whether removing it or not
currentNode = currentNode.getNextNode();
Iterator.remove()
This problem you are describing shows the usefulness of Iterator.remove() when using data structures from the JDK for going through an iterable collection and removing elements as you go through it.

After removing a node, as #Vakimshaar suggested, you need to decrement the i because the node at this index has been removed and there is a new node at the same index. In addition to that, you also need to update the currentNode reference as it would still be pointing to the node you've just removed, but it should really be pointing to the new node that has moved to this index.
So in the if (item.equals(currentNode.getData())){ block you need to do the following:
Node nextNode = currentNode.getNextNode();
index++;
remove(i--);
currentNode = nextNode;
With this, your code should correctly remove all occurrences.

Here is a Java Code to delete all occurrences of an item from a linked list :
public class LinkedList{
Node head;
class Node{
int data;
Node next;
Node(int d){data =d; next = null;}
}
public void push(int new_data){
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
public void insertAfter(Node givenNode, int new_data){
if(givenNode == null)
System.out.println("Given node cannot be empty");
Node new_node = new Node(new_data);
new_node.next = givenNode.next;
givenNode.next = new_node;
}
public void append(int new_data){
Node new_node = new Node(new_data);
if(head == null)
head = new_node;
else{
Node last = head;
while(last.next != null)
last = last.next;
last.next = new_node;
}
}
public void printList(){
Node temp = head;
while(temp != null){
System.out.println(temp.data + " ");
temp = temp.next;
}
}
void deleteNode(int key){
// Store head node
Node temp = head, prev=null;
// If head node itself holds the key or multiple occurrences of key
while(temp != null && temp.data == key){
head = temp.next;
temp = head;
}
// Delete occurrences other than head
while(temp != null){
// Search for the key to be deleted, keep track of the
// previous node as we need to change 'prev.next'
while(temp != null && temp.data != key){
prev = temp;
temp = temp.next;
}
// If key was not present in linked list
if(temp == null) return;
// Unlink the node from linked list
prev.next = temp.next;
//Update Temp for next iteration of outer loop
temp = prev.next;
}
}
public static void main(String[] args){
LinkedList llist = new LinkedList();
llist.push(6);
llist.append(7);
llist.append(7);
llist.append(7);
llist.append(9);
llist.push(10);
llist.deleteNode(7);
llist.printList();
}
}
Output :
10
6
9

Related

Removing an element by index in a linked list

A method for removing an element from a linked list has been implemented:
public void remove(T e) {
Node<T> node = first;
Node<T> prevNode = null;
while(node != null){
if(e.equals(node)){
if(prevNode == null) {
first = node.next;
}
else {
prevNode.next = node.next;
}
size--;
}
else {
prevNode = node;
}
node = node.next;
}
}
How to correctly implement deleting an element by index? Using the capabilities of the remove method.
public void removeByIndex(int i) {
remove(i);
}
Something like this should work:
public void remove(int i) {
if (i >= size || i < 0) {
throw new ArrayIndexOutOfBoundsException();
}
Node<T> remove;
if (i == 0) {
remove = first;
first = first.next;
first.prev = null; // <- For double linked list
} else {
Node<T> node = first;
for (int j = 0; j < i - 1; ++j) {
node = node.next;
}
remove = node.next;
if (i == size - 1) {
node.next = null;
} else {
node.next.next.prev = node; // <- For double linked list
node.next = node.next.next;
}
}
// Clear links from removed Node
remove.next = null;
remove.prev = null; // <- For double linked list
size--;
}
Find the node before position i. Point that node to the "over next" node.
Edit
The original code example was a rough sketch at best. Updated with a more complete version.
Edit #2
Slight improvements:
Clears links from the removed node
Also handles double linked lists
remove(get(i));
This is not the most efficient solution, but a simple one which uses the remove(T) method. You call it with get(i) as the object to be removed - which is the element at the specified index.
Note: This solution has some issues if the list has duplicate values, but in that case you shouldn't use the remove(T) method anyway. If you want it to be safe, iterate to the specified index:
Node<T> node = first;
for(int i=0;i<index;i++){
prevNode=node;
node=node.next;
}
and do this:
node.prev.next=node.next;
node.next.prev=node.prev;
size--;
Of course, this is just a rough implementation. To ensure full compability, you should check if the index is valid and use the unlink(Node) method of LinkedList.
The LinkedList also has an implementation for the remove(int) method:
checkElementIndex(index);
return unlink(node(index));

Delete a node from Singly Linked list at any index using a single method/function in java

I want to create and delete a node from the singly linked list in java. The deleting method will take the index of node and delete that node.
The logic is working but it is not deleting the node at first index (0) how do i modify this code so that it can delete node at any position without using extra loops. I know that I am using starting index as 1 in code but I can not riddle this that if entered index is zero then how the program can delete the "previousNode" using the same loop. It will require another loop (based on this logic). Is there a way to remove this extra loop
public E deleteNode(int t) throws IndexOutOfBoundsException{
if(size==0)
return null;
if(t>=size)
throw new IndexOutOfBoundsException("Invalid Input");
Node<E> previousNode=head;
Node<E> currentNode=previousNode.getNext();
int currentIndex=1;
while(currentIndex<t){
previousNode=previousNode.getNext();
currentNode=previousNode.getNext();
currentIndex++;
}
previousNode.setNext(currentNode.getNext());
size--;
return currentNode.getElement();
}
If user enters the index 0, then the output of {1,2,3,4} should be {2,3,4} but I get {1,3,4}.
One option would be to handle it as a special case as it requires updating head.
if (t == 0) {
head = head.getNext();
}
//rest of your code..
Node<E> previousNode=head;
//...
Or, you can do like
Node<E> previousNode = null;
Node<E> currentNode = head;
int currentIndex = 0;
while(currentIndex < t) {
previousNode = currentNode;
currentNode = currentNode.getNext();
currentIndex++;
}
if (previousNode == null) { //removing first node
head = head.getNext();
} else {
previousNode.setNext(currentNode.getNext());
}
size--;
return currentNode.getElement();
But anyway you need to handle it as a special case.

Java - Removing an element from LinkedList except first

I'm new to Java.
I have created a method where it will remove elements from LinkedList except the first one. The idea is a boolean will be set to true if a LinkedList's element data (Which is in Integer) matched with parameter. Once the boolean sets to true, it will remove any element that also matched with initial one.
Now for the problem. For example, if I were to remove 5 except the first one from this LinkedList:
5 5 5 6 5 7 8 9
I will get result like this:
5 5 6 7 8 9
As you can see, it didn't remove the 5 on the second position. Is there anything wrong with my code?
Here's the code by the way
public void append(int data) {
Node newNode = new Node(data);
if (head == null) {
head = new Node(data);
return;
}
Node lastNode = head;
while (lastNode.next != null) {
lastNode = lastNode.next;
}
lastNode.next = newNode;
return;
}
public void insert(int data) {
Node newData = new Node(data);
newData.next = head;
head = newData;
}
public void removeExceptFirst(int dataValue) { //The mentioned method
boolean duplicate = false;
Node currentNode = head;
while (currentNode.next != null) {
int value = currentNode.next.data;
if (value == dataValue) {
if (!duplicate) {
duplicate = true;
currentNode = currentNode.next;
} else {
currentNode.next = currentNode.next.next;
}
} else {
currentNode = currentNode.next;
}
}
return;
}
The problem here is with
if (!duplicate) {
duplicate = true;
currentNode = currentNode.next;
}
you are marking duplicate = true and immediately assigning the "currentNode = currentNode.next;"
due to this reference is getting preserve of the next node
So
1. Put the condition outside of the loop to check whether the head element itself is
that node, if->yes mark isDuplicate = true and proceed in the loop.
2. Inside the loop check afterward and then assign the next node.
Hope this should work
You skipped head node. Try replace
Node currentNode = head;
with
Node currentNode = new Node();
currentNode.next = head;
You should update the current node reference as well as head->next should point to the current node after removing the node.
try the below code:
if (!duplicate) {
duplicate = true;
currentNode = currentNode.next;
head.next= currentNode.next;
}else {
currentNode.next = currentNode.next.next;
currentNode = currentNode.next;
head.next = currentNode; }
`

Implementing a remove method for a doubly linked list

I'm trying to implement a doubly linked list for a class assignment. I am currently stuck on implementing a method to remove a node at a specified index.
public void remove(int index) {
if (index < 0 || index > count-1) {
throw new ListIndexOutOfBoundsException("The index "+index+" is out of bounds.");
}
if (isEmpty()) {
System.out.println("List is empty");
return;
}
MedicationNode curr = head;
int k = 0;
while(k < index) {
curr = curr.next;
k++;
}
if (curr.prev == null) {
curr.next.prev = null;
}else if(curr.next == null) {
curr = curr.prev;
curr.next = null;
}else{
curr.next.prev = curr.prev;
curr.prev.next = curr.next;
}
count--;
}
the method can remove any specified node in a linked list except index 0. I'm thinking the problem may be with my add method but im not really sure.
In your first if condition -
if (curr.prev == null) {
curr.next.prev = null;
//Make your head of the linked list point to this node
head = curr.next;
}
This is because you are removing the head from the list so the head should point to the head's next node.

Doubly Linked List of Menu Items

I have a program which processes menu items (and submenu items) using a linkedList data structure. My program works except for the delete function which works if deleting an element inserted before an existing element but doesn't if the element is inserted after an existing element. Any advise is much appreciated! Here's the insert function
public Item insert(String newElem, String existingElem, int key) {
// search for given existing element starting at head
currentNode = new Item("");
currentNode = head;
while (!currentNode.element.equals(existingElem)) {
currentNode = currentNode.next;
if (currentNode == null)
break; // cannot find the given key
}
// create a new node
newNode = new Item(newElem);
if (key == 1) // if key = 1 insert after the existing element
{
newNode.next = currentNode.next;
newNode.prev = currentNode;
currentNode.next = newNode;
tail = newNode;
tail.next = null;
counter++;
}
if (key == 2) // if key = 2 insert before the existing element
{
newNode.next = currentNode;
newNode.prev = currentNode.prev;
currentNode.prev = newNode;
head = newNode;
head.prev = null;
counter++;
}
return newNode;
}
I also realize that I am assuming only one existing element, however, if I could make the delete function more generic then it would be best and I don't want to split the function into multiple functions! Here's the delete function:-
public Item delete(String elem) {
// search for given existing element starting at head
currentNode = new Item("");
currentNode = head;
while (!currentNode.element.equals(elem)) {
currentNode = currentNode.next;
if (currentNode == null)
break; // cannot find the given key
}
// check if element is the first element
if (currentNode == head) {
head = currentNode.next;
} else {
currentNode.prev = currentNode.next;
}
// check if element is the last element
if (currentNode == tail) {
tail = currentNode.prev;
} else {
currentNode = currentNode.prev;
}
return currentNode;
}
Problems
You should not be updating tail and head every time you insert a new node. You should only do so if inserting at the beginning or end of the list, if you are not at the begining of the list, you need to also update the prev/next of the element that used to be before/after the one you are inserting next to:
if (key == 1) // if key = 1 insert after the existing element
{
newNode.next = currentNode.next;
newNode.prev = currentNode;
currentNode.next = newNode;
if (newNode.next == null)
tail = newNode;
else
newNode.next.prev = newNode;
}
else if (key == 2) // if key = 2 insert before the existing element
{
newNode.next = currentNode;
newNode.prev = currentNode.prev;
currentNode.prev = newNode;
if (newNode.prev == null)
head = newNode;
else
newNode.prev.next = newNode;
}
Note: I am also using an else if statement, instead of two ifs
Your delete function need to be updated also. You are not updating the surrounding nodes, just the one you are removing:
if (currentNode.prev == null) { // is head
head = currentNode.next;
} else {
currentNode.prev.next = currentNode.next;
}
if (currentNode.next == null) { // is tail
tail = currentNode.prev;
} else {
currentNode.next.prev = currentNode.prev;
}
Other comments
It seems unusual that you would be searching for the node to insert before/after by value, what if I had a list like this: [1,2,2,2,3]? It would be impossible to insert a value in several places in that list. Surely your API should be based on Items:
public Item insert(String newValue, Item existingItem, int key);
public Item delete(Item item);
Or indicies:
public Item insert(String newValue, int index, int key);
public Item delete(int index);
You can then have another method to find the Item or index for a particular value:
public Item find(String value);
Or:
public int indexOf(String value);
And use them like this to get the equivalent of your methods:
list.insert("value", list.find("other value"), 1);
You might want to consider changing the insert method to an insertBefore and insertAfter method, or at least changing the key parameter to an enumerated type:
public enum Position {
BEFORE,
AFTER,
}
After all, what happens when key is 0, or 23?
You currently have currentItem as a class member, it should really be a local variable of the function (after all, what use does it have outside of those functions), and you also don't need to initialise it to a new element, just set it straight to head:
public Item insert(String newElem, String existingElem, int key) {
Item currentNode = head;
...
}
Finally, your search code doesn't work if there are no items in the list. The following line will fail with a NullPointerException if head is null:
while (!currentNode.element.equals(existingElem))
Because you can't call .equals(...) on a null reference.

Categories