Java - Removing an element from LinkedList except first - java

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; }
`

Related

Remove duplicates from a sorted linked list in a efficient way

I'm on HackerRank and I need to remove duplicate items from a sorted linked list. I passed all the cases except for two of them which the input is something like: 10001102034
So my program takes to seconds to complete and exceed the time. How can I do my code more efficiently, I heard about using square root but I don't know how to use it. Any guide is appreciate. Here is my code.
private static Node removeDuplicates(Node head) {
/* Another reference to head */
Node current = head;
Node next;
/* Traverse list till the last node */
while (current != null && current.next != null) {
if (current.data == current.next.data) {
next = current.next.next;
if (next == null) {
current.next = null;
break;
}
current.next = next;
} else {
current = current.next;
}
}
return head;
}
Again. It works but takes too much times with longer numbers.
You should replace condition if (current.data == current.next.data) with while loop and use break 'label':
out:
while (current != null && current.next != null) {
while (current.data == current.next.data) {
next = current.next.next;
if (next == null) {
current.next = null;
break out;
}
current.next = next;
}
current = current.next;
}
You can't use the square root because when u want to remove duplicates from a list you have to check all the list .
The square root technique is used for searching in a sorted list.
But for your question if you can improve the runtime on that your code in O(n^2) but if you change your code to use hashtable you can make it O(n).
import java.util.HashSet;
public class removeDuplicates
{
static class node
{
int val;
node next;
public node(int val)
{
this.val = val;
}
}
/* Function to remove duplicates from a
unsorted linked list */
static void removeDuplicate(node head)
{
// Hash to store seen values
HashSet<Integer> hs = new HashSet<>();
/* Pick elements one by one */
node current = head;
node prev = null;
while (current != null)
{
int curval = current.val;
// If current value is seen before
if (hs.contains(curval)) {
prev.next = current.next;
} else {
hs.add(curval);
prev = current;
}
current = current.next;
}
}
/* Function to print nodes in a given linked list */
static void printList(node head)
{
while (head != null)
{
System.out.print(head.val + " ");
head = head.next;
}
}
I hope this will help you.

Remove Duplicates from Linked List

So I have a linked list that I am trying to remove duplicates from.
My basic algorithm that I thought up is to pretty much use the runner technique. Where I keep two pointers to compare adjacent elements. If they are the same I change the pointer of p1 to point to p1.next.next if not I keep traversing the list. However I keep getting a null pointer exception in the solution I have typed.
Node RemoveDuplicates(Node head) {
// This is a "method-only" submission.
// You only need to complete this method.
if (head == null){
return null;
}
Node current = head;
Node runner = head;
while(current != null && runner != null && runner.next != null){
runner = runner.next;
if(runner.data == current.data){
if(current.next != null){
current = current.next.next;
}
}else{
current = current.next;
}
}
return current;
}
At the point that I exit the while loop current is null. Which I think is the problem. How would I return the head of the altered list.
OK, although you've already accepted an answer, here's some example code using recursion to remove the dups from an ordered list per your request in the comments. (if your list isn't ordered, order it :) )
public Node removeDups(Node root) {
if (root.next == null)
return root;
root.next = removeDups(root.next);
if (root.data == root.next.data)
return root.next;
return root;
} // call as root = removeDups(root);
As you mentioned, recursion isn't really necessary here but you're using a Node-based linked list which is recursively defined. So, when it makes sense, the elegance of the solution has its benefits.
What I like about it is that you're not doing any node.next.next or needing to check for that null case. Once the stack starts unwinding, you're already in a position to start checking for dups. Then it's just a matter of comparing root.data and root.next.data; both of which you already know exist.
You can do this with single traversal with 2 pointer.and also this code works with single while loop.
public Node deleteDuplicates(Node head) {
Node current=head;
if (head == null)
return null;
else
{
Node runner=head.next;
while(head.next!=null && runner!=null)
{
if(head.val == runner.val)
prev=runner.next;
else
{
head.next=runner;
head=head.next;
prev=runner.next;
}
}
head.next=runner;
}
return current;
}
First of all, you'll want to return head at the end, so that you are returning the list, not just the last element.
Second thing, you'll want to modify the .next references instead of assigning them in some of the cases.
Note this doesn't work if the list isn't sorted.
Before: 1 1 3 3
After: 1 3
This code works (and I've tested it)
static Node RemoveDuplicates(Node head) {
if (head == null) return null;
Node current = head;
Node runner = head;
while (current != null && current.next != null) {
runner = current.next;
while (runner != null && runner.data == current.data) {
current.next = runner.next; // skip the repeat
runner = runner.next;
}
current = current.next;
}
return head;
}
You can do this in a single traversal. Just maintain two pointers temp
and next_of_next. Make temp iterate for each node and when the data of temp and the next node is equal, point next_of_next to the alternate node after temp and delete the node after temp.
Node removeDuplicates(Node head)
{
Node temp = head;
Node next_of_next;
if (head == null)
return;
while (temp.next != null)
{
if (temp.data == temp.next.data)
{
next_of_next = temp.next.next;
temp.next = null;
temp.next = next_of_next;
}
else
temp = temp.next;
}
return head ;
}
Here an apporach without recursion using a HashSet:
public void RemoveDuplicates()
{
if (head != null)
{
var hm = new HashSet<T>();
Node current = head;
Node prev = null;
while (current != null)
{
if (!hm.Contains(current.Value))
{
hm.Add(current.Value);
prev = current;
current = current.Next;
}
else
{
prev.Next = current.Next;
current = prev.Next;
}
}
}
return head;
}

Issues with reversing the linkedlist

I'm trying to learn about linked list and it has been little challenging for me. I'm trying to reverse the link list with recursive method. Here is my code:
public class ListNode {
Node head = null;
int nodeCount= 0;
int counter = 0;
ListNode(){
head = null;
}
public void insertNode( String name ) {
if (head == null) {
head = new Node(name, null);
nodeCount++;
} else {
Node temp = new Node(name, null);
temp.next = head;
head = temp;
nodeCount++;
}
}
public Node reverseTest(Node L){
// Node current = new Node(null,null);
if(L == null || L.next ==null){
return L;
}
Node remainingNode = reverseTest(L.next);
Node cur = remainingNode;
while(cur.next !=null){
cur=cur.next;
}
L.next = null;
cur.next = L;
return remainingNode;
}
public static void main(String[] args){
ListNode newList = new ListNode();
newList.insertNode("First");
newList.insertNode("Second");
newList.insertNode("Third");
newList.insertNode("Fourth");
newList.reverseTest(newList.head);
}
}
The problem I'm having with is the reverse method. When the method is over it only returns the last node with the value "First".Through the entire recursion remainingNode only holds and returs value from the base case which is confusing me. I was excepting it to move further through the nodes. After the method is executed newList holds only one node with next node as null and that node is the head now. I was assuming it will reverse the linkedlist with the sequence First --> Second--> Third --> Fourth. What am I doing wrong?
Actually, everything works here. Your only problem is in your main method: you don't get the result of your method.
newList.reverseTest(newList.head);
You need to actually set the new head with the result:
newList.head = newList.reverseTest(newList.head);
This would have been easier to see if you had declared your method static:
newList.head = ListNode.reverseTest(newList.head);
As a bonus, here is a fully recursive equivalent:
public static Node reverse(Node head) {
if (head == null || head.next == null) {
return head;
}
Node newHead = reverse(head.next);
// head.next points to the new tail, we push the former head at the end
head.next.next = head;
// now head has become the new tail, we cut the end of the list
head.next = null;
return newHead;
}

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.

Remove all occurrences of item from a Linked List

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

Categories