Deleting Node with same data in 2 LinkedLists - java

as the title says, i want to compare 2 linked Lists ( Done and working ) and i want to delete Nodes with same values ONLY IN LIST 2 .. i wrote a code and tried it out, it works in specific cases but i can't seem to understand what's going on with it ( giving wrong outputs ). the idea i used is sticking a LinkedList at a node, comparing it with all the nodes in the other List then delete whenever it finds they are equal.
Here is the delete head code :
public void deleteHead() {
if (head != null) {
head = head.getNext();
}
}
and here is the CompareTo Code :
public int compareTo(NodeData nd) {
if (num == nd.getNum()) {
return 0;
}
if (num != nd.getNum()) {
return -1;
}
return 1;
}
And this is the Delete method
public void delete(LinkedList LL) {
Node curr = head;
Node curr2 = LL.head;
while (curr2 != null) { //To traverse LL when list1 is done traversing
while (curr != null) { //traverse list1 while checking for common Nodes to delete
if (curr2.getData().compareTo(curr.getData()) == 0) { //compare data in the Nodes
System.out.println(curr2.getData().getNum() + " FOUND, WILL BE DELETED");
deleteHead(); //delete the current node of list1
curr = curr.getNext();
break;
}
else if (curr2.getData().compareTo(curr.getData()) == -1 ){
System.out.println(curr2.getData().getNum() + " Doesn't Match");}
curr = curr.getNext(); //next node in list1
}
curr2 = curr2.getNext(); //next node in LL
}
}
i tried with a simple output :
Output

If the data of two nodes equals you're deleting the head of one of the lists instead of the current node.
Second, you should compare each element of the first with each element of the second list, the inner while loop will iterate and consume the second list, and when it's called again - there'll be nothing to iterate, so you should probably change:
while (curr2 != null) { //To traverse LL when list1 is done traversing
while (curr != null) { //traverse list1 while checking for common Nodes to delete
to:
while (curr2 != null) {
Node curr = head; // <-- pay attention here, every loop you need to start from the beginning!
while (curr != null) {
if ... {
delete(curr); // TODO: need to implement this method in your LinkedList class
else {
...

Related

How to rearrange elements in a LinkedList so that negative numbers come first? And it successfully ends the loop?

I am a beginner, below is the best that I could come up so far. The objective of the method .Split() is that I am supposed to rearrange (rearrange only, no adding or removing nodes nor switching data of the nodes) the elements of the LinkedIntList <- This is not that standard LinkedList class, its a modified class that I have to use, there is no Java method that I can use for this problem unfortunately.
For example, if a linkedlist is [1, 5, -9, 7, -5, 78], the result should be [-9,-5, 1, 5, 7, 78]. The order of the negative values do not matter.
There is only one private field, which is ListNode front;
I am trying to use current.data < 0 to pick out the negative values and put them at the front of the list, iterating from the front, and start over. Making sure that it selects all the negative values from the list. But my output keeps getting stuck in a endless loop, unable to break. I am not sure what to do here.
Here is my best attempt at this problem.
public void Split()
{
ListNode current = front;
ListNode head = front;
while (current.next != null)
{
if (current.data < 0)
{
current.next = front; // set the pointer of current's node
front = current; // update the head with a negative value
current = current.next; // iterate from the front
}
else if (current.data >= 0)
{
current = current.next; // if positive, skip the process and keep iterating
}
else
{
break; // break if null or anything else
}
if (current.next == null || current == null)
{
break; // another attempt to break since it keeps getting stuck
}
}
}
hi llda: in order to move negative numbers ahead, I suggest get it done via two adjacent pointers. See the demo idea picture attached.
The code shows below:
public void Split(){
ListNode current = front.next;
ListNode prior = front;
ListNode head = front;
do {
if(current.data < 0 && current.next != null){
prior.next = current.next;
head = current;
head.next = front;
current = prior.next;
}
current = current.next;
prior = prior.next;
} while(current.next != null)
}
You have to update all related references to keep the linked list intact.
As a homemade implementation, I would suggest a full sort (a kind of bubblesort) this way:
...
public void sort() {
ListNode item = front;
while (item.next != null) {
if (needSwapping(item, item.next)) {
item = swapItems(item, item.next);
if (item.prev != null) {
// one step back to check next against prev in next loop
item = item.prev;
}
} else {
item = item.next;
}
}
front = firstNode(item);
}
private ListNode swapItems(ListNode item, ListNode next) {
ListNode outerPrev = item.prev;
ListNode outerNext = next.next;
// change the refs of outer elements
if (outerPrev != null) {
outerPrev.next = next;
}
if (outerNext != null) {
outerNext.prev = item;
}
// change refs to outer elements
item.next = next.next;
next.prev = item.prev;
// change inner refs
item.prev = next;
next.next = item;
return next;
}
private boolean needSwapping(ListNode item, ListNode next) {
return item.data > next.data;
// here is the point for optimizations of sort accuracy eg. negatives order doesn't matter
// return item.data >0 && item.data > next.data;
}
...
But much more modern Java Style would be to implement the Comparable interface or to provide a Comparator and make use of the Collections.sort method as described here or at stackoverflow.

Is there a cleaner or more efficient way to remove all values in a sorted linked list that appear in another sorted linked list?

I'm currently doing some practice problems for a course I'll be taking in the fall and I ran into this question:
Write a method removeAll that could be added to the LinkedIntList class. The method should efficiently remove from a sorted list of integers all values appearing in a second sorted list of integers. For example, suppose LinkedIntList variables list1 and list2 refer to the following lists:
list1: [1, 3, 5, 7]
list2: [1, 2, 3, 4, 5]
If the call list1.removeAll(list2) is made, the lists should store
the following values after the call:
list1: [7]
list2: [1, 2, 3, 4, 5]
Both lists are guaranteed to be in sorted (non-decreasing) order, although there might be duplicates in either list. Because the lists are sorted you can solve this problem very efficiently with a single pass through the data. Your solution is required to run in O(M + N) time where M and N are the lengths of the two lists.
You may not call any other methods of the class to solve this problem, you may not construct any new nodes, and you may not use any auxiliary data structures to solve this problem (such as an array, ArrayList, Queue, String, etc.). You also may not change any data fields of the nodes. You must solve this problem by rearranging the links of the lists.
In order to solve this problem, there's a custom LinkedIntList and ListNode class that's provided.
public class LinkedIntList {
private ListNode front; // head of the list
...
}
public class ListNode {
public int data; // value stored in this node of the list
public ListNode next; // reference to next node in the list (null if end of list)
...
}
I solved this question in O(M + N) time in one pass. However, I'm wondering if there's any way to solve this question more efficiently. I have a nested if-else block within an if-statement and I think it could be cleaned up. I have included my code below.
public void removeAll(LinkedIntList list2) {
if (this.front != null && list2.front != null) {
// iterators for the list to remove values from
ListNode prev = null;
ListNode current = this.front;
// iterator for the list where values from list1 may appear
ListNode list2Current = list2.front;
// reference to the front of list1
ListNode head = current;
while (current != null && list2Current != null) {
while (current != null && current.data < list2Current.data) {
prev = current;
current = current.next;
}
while (current != null && list2Current != null && list2Current.data < current.data) {
list2Current = list2Current.next;
}
if (current != null && list2Current != null && current.data == list2Current.data) {
// prev can only be null if current is still pointing at the front of list1
if (prev == null) {
ListNode nextup = current.next;
current.next = null;
current = nextup;
head = current;
} else {
prev.next = current.next;
current = prev.next;
}
} else if (current != null) {
prev = current;
current = current.next;
}
}
front = head;
}
}
There's no faster than O(M+N) solution to this problem as all elements of both list should be iterated over.
However, the solution could be coded simpler, for example:
public void removeAll(LinkedIntList list2) {
ListNode previous = front;
ListNode current = front;
ListNode toRemove = list2.front;
while (current != null && toRemove != null) {
if (current.data < toRemove.data) {
previous = current;
current = current.next;
} else if (current.data > toRemove.data) {
toRemove = toRemove.next;
} else {
if (current == front) {
front = current.next;
} else {
previous.next = current.next;
}
current = current.next;
}
}
}
You've got the right idea for your solution. This problem requires that you examine each entry in the list at least once, so by definition you can't do any better than single-pass linear time. I believe you found the optimal solution.
Some notes about your code:
if (prev == null) {
ListNode nextup = current.next;
current.next = null;
current = nextup;
}
You detached the node to be deleted, but you never attach the next node (the new current) to the list. Your list head will still be pointing to the "deleted" node. (I think you may have tried to fix this problem with front = head at the end of the loop, but you never update head, so that doesn't really have any effect. I would just remove that line altogether.)
Here's how I would rewrite the if:
if (current != null && list2Current != null && current.data == list2Current.data) {
if (prev == null) {
this.first = current.next;
} else {
prev.next = current.next;
prev = current;
}
current = current.next;
}
Regarding the else if: the only way both the while loops exited is if
We reached the end of this list, in which case we're done; OR
We reached the end of list2, in which case we're done; OR
The data at the current node of this list == the data at the current node of list2
So theoretically, you don't even need to check for equality. There's no situation in which you both need to continue and end up inside that else branch.
There are other ways to make this same solution with cleaner code (like #MartinBG's answer), but I tried to clean up your code specifically.

Singly Linked List Delete Value

I am making a singly linked list where I need to put a delete method but getting error any help?
public void remove(int index) {
getNode(index - 1).Next = getNode(index + 1);
}
Many possible errors can happen here. For one, I definitively would put more verification before making any changes as if
Are you on the first element (Then the header would be then 2nd element);
Are you on the last element (then is getNode(index+1) returning correctly NULL or throwing an exception)?
Like Apokai rightly noted you need to take extreme care while deleting.
Here are three methods for deleting use whichever serves the purpose:
//Method to delete the first/head element
public void deleteAtFirst() {
if (head == null) {//If list is empty
System.out.println("Linked List EMPTY!!");
} else {//else if it is not empty
head = head.next;//assigning head the address of the next node
}
}
//Method to delete the last element
public void deleteAtLast() {
if (head == null) {//If list is empty
System.out.println("Linked List EMPTY!!");
} else if (head.next == null) {//else if it has only 2 elements
head = null;
} else {//else if it is not empty and has more than 2 elements
Node tmpNode = head;//taking a temporary node and initialising it with the first/head node
while (tmpNode.next.next != null) {//looping it till the 'second last' element is reached
tmpNode = tmpNode.next;
}
tmpNode.next = null;//assigning the next address of the second last node as null thus making it the last node
}
}
//Method to delete an element at a given position
//The first element is situated at 'Position:[0]'
public void deleteAtPosition(int pos) {
int size = getSize();//Getting the size of the linked list through a pre-defined method
if (head == null || pos > size - 1) {//if the position is beyond the scope of current list or the list is empty
System.out.println("Position: " + pos + "does not exist");
} else {
Node prevNode = null;
Node currNode = head;
if (pos == size - 1) {//if position is equal to size-1 then essentially the last element is to be deleted
deleteAtLast();
} else if (pos == 0) {//if position given is '0' then we need to delete the first element
deleteAtFirst();
} else {//else if it is any other valid position
for (int i = 0; i < pos; i++) {//looping till the desired position
prevNode = currNode;//the node just before the required position will be assigned here
currNode = currNode.next;//the current node
}
prevNode.next = currNode.next;//assigning the next address of previous node to the next of current node thus removing the current node from the list
}
}
}
Take care that if you use the last one then the above two methods are present in your code. Also it uses another method getSize() :
//Method to get the size of the list
public int getSize() {//return type is integer as we are returning 'int size'
if (head == null) {//if the list is empty
return 0;
}
int size = 1;//initialising size by one
Node tmpNode = head;//taking a temporary node and initialising it with the first/head node
while (tmpNode.next != null) {//looping till the end of the list
tmpNode = tmpNode.next;//incrementing node to the next node 'after every iteration' of the loop
size++;//incrementing the size
}
return size;//returning size
}

Finding the right place and storing in LinkedList

I am trying to store the strings in a LinkedList. I am not allowed to pre-sort, but find the place and pass the string to the linked list. When i pass the strings through text file, the string do not go through the last else condition.
My input file has
joe
appy
appz
zebra
cat
When it reaches appz, it doesn't go through any statement. It is supposed to insert the last else condition and print 5, but doesn't do that.
/**
* Gets the string and arranges them in order
* #param newString
*/
public void store(String newString) {
LinkedListNode current = head;
System.out.println(newString);
// if no element in the list
if (current==null){
System.out.println("1");
makeNode(newString);
}
// if only 1 elements in the list
else if(current.getNext()==null ){
System.out.println("2");
if(newString.compareTo(current.getName())<0){
insertBefore(current.getName(),newString);
} else{
insertAfter(current.getName(),newString);
}
}
// if the element is smaller than the head in the list
else if(newString.compareTo(current.getName()) < 0){
System.out.println("3");
LinkedListNode temp = makeNode(newString);
temp.setNext(current);
head=temp;
}
// if the element is greater than the tail in the list
else if(newString.compareTo(findTail().getName()) > 0){
System.out.println("4");
insertAfter(findTail().getName(),newString);
}
// for more than two elements in the list
else{
System.out.println("5");
while(!(newString.compareTo(current.getName())>0 && newString.compareTo(current.getNext().getName())<0 ) && current.getNext()!=null){
current=current.getNext();
}
if(newString.compareTo(current.getName())<0){
insertBefore(current.getName(),newString);
}
else{
insertAfter(current.getName(),newString);
}
}
} // end of store()
You have some issue with the insertBefore. I updated it.
public void insertBefore(String later, String name){
if(head==null){
head = new LinkedListNode(name,null);
}
else if(head.getName()==later){
LinkedListNode newNode = makeNode(name);
newNode.setNext(head);
head=newNode;
}
else{
LinkedListNode current = head;
while(current.getNext().getName()!=later){
current=current.getNext();
}
LinkedListNode newNode = makeNode(name); // create the new node
newNode.setNext(current.getNext());
current.setNext(newNode);
}
} // end of insertBefore()
When you are traversing, you are not supposed to change the head reference. To traverse, simply do this:
Node tmp = head;
while(tmp != null) tmp = tmp.next;
This will become very handy to figure out where to insert new nodes or where to go to remove existing nodes.
Your class should also have methods to addFirst, addLast, insertBefore, insertAfter. In the code below, Object is whatever data type your need (in your case, String)
public void addLast(Object item)
{
if(head == null)
{
addFirst(item);
}
else
{
Node<Object> tmp = head;
while(tmp.next != null)
{
tmp = tmp.next;
}
tmp.next = new Node<Object>(item, null);
}
}
public void addFirst(Object item)
{
head = new Node<Object>(item, head);
}
public void insertAfter(Object key, Object item)
{
Node<Object> tmp = head;
while(tmp != null && !tmp.data.equals(key))
{
tmp = tmp.next;
}
if(tmp != null)
{
tmp.next = new Node<Object>(item, tmp.next);
}
}
public void insertBefore(Object key, Object item)
{
if(head == null)
{
return null;
}
if(head.data.equals(key))
{
addFirst(item);
return;
}
Node<Object> previous = null;
Node<Object> current = head;
while(current != null && !current.data.equals(key))
{
previous = current;
current = current.next;
}
//insert between current and previous
if(current != null)
{
previous.next = new Node<Object>(item, current);
}
}
In my opinion, you should not have a nested if/else construct to figure out where to insert. That should be up to the method you are invoking.
Secondly, the conditions you are using to control the flow of execution in your code are disparate. Your IF condition is if the list is empty. If it is, create a new node and add it to the list. That condition is followed by checking for a list containing only one node. After that, you are not checking for the length of the list. The expected logic is that you should be checking for a list size greater than one; and yet this is your fall through case (the last else). If you are going to be doing that kind of check outside the insert methods, then do something like this (stubbing your code):
if (current==null){
System.out.println("1");
makeNode(newString);
}
// if only 1 elements in the list
else if(current.getNext()==null ){
System.out.println("2");
if(newString.compareTo(current.getName())<0){
insertBefore(current.getName(),newString);
} else{
insertAfter(current.getName(),newString);
}
}
// if the list has more than one element
else
{
// figure out where it goes (before or after) and insert
}
If you notice, the else/if and else blocks do basically the same thing. Therefore, your code can (and should) be simplified as follows:
if (current==null){
System.out.println("1");
makeNode(newString);
}
// if the list has one or more elements
else
{
// figure out where it goes (before or after) and insert
}

How to delete a specific node in a linked list

I previously needed help debugging my deleteNode method. It works now (updated version posted below) but I want it to provide for the case when it has to delete the head node. At the moment, it returns a NullPointerException where I've inserted * in deleteNode. I don't know how any of my variables can be null at that point, seeing as my while loop requires both position and head to not be null in the first place.
public class LinkedList
{
private class Node
{
int item;
Node link;
#SuppressWarnings("unused")
public Node()
{
item = Integer.MIN_VALUE;
link = null;
}
public Node(int x, Node p)
{
item = x;
link = p;
}
}
private Node head;
public LinkedList()
{
head = null;
}
public boolean deleteNode (int target)
{
Node position = head;
boolean isGone = false;
while(position != null && head != null)
{
if(position.link == head && position.link.item == target)
{
head = head.link;
isGone = true;
return isGone;
}
*** else if(position.link.item == target && position.link != head)
{
position.link = position.link.link;
isGone = true;
return isGone;
}
position = position.link;
}
return isGone;
}
public void printList()
{
System.out.println("Your list is: ");
Node position = head;
while(position != null)
{
System.out.println(position.item + " ");
position = position.link;
}
System.out.println();
}
}
LinkedList.deleteNode(int) never modifies any node's link, so it doesn't remove any element from the list.
Suppose that nodeA.link == nodeB, and nodeB.item == target. Then you need to set nodeA.link = nodeB.link, so that nothing is pointing to nodeB anymore.
Here is a list of the problems I see:
The enumerator you actually want to use, position, is never updated. The enumerator that is updated, counter is not needed.
You are never actually removing the node. In order to remove the node, you need to set the previous node's link to the matching node's link, thus removing it out of the chain.
You aren't dealing with special cases. What happens if the list passed is null? What happens if the matching node is the first node? The last node?
You should be returning the head of the linked list from the calling function. This is required for when removing the head node of the linked list.
Since this is a homework question, try to work it out for yourself but hopefully those points will help.
Look at your deleteNode() while loop code.
while(position != null && counter != null)
{
itemAtPosition = position.item;
if(itemAtPosition == target)
{
position = position.link;
isGone = true;
}
counter = counter.link;
}
you update counter, but never refer to it. position never changes, so the
if(itemAtPosition == target)
line never returns true. I suspect somewhere you need to check on counter.item!
First, you didn't write code for the case where the target item is located at the beginning, in which the field head should be updated accordingly. Second, the compared item is never updated during traversing the list.

Categories

Resources