I do not see my mistake, correct me, please!
I need to delete an object from Linkedlist. But I got an error NPE in if (current.item.equals(e))
public void remove(T e) {
if (first == null) {
throw new IndexOutOfBoundsException("List is empty");
}
if (first.item.equals(e)) {
first = first.next;
first.next.prev = null;
}
if (last.item.equals(e)) {
last = last.prev;
last.prev.next = null;
} else {
Node<T> current = first;
for (int a = 0; a < size; a++) {
current = current.next;
if (current.item.equals(e)) {
current.prev.next = current.next;
current.next.prev = current.prev;
}
}
size--;
System.out.println("Removed");
}
}
Linkedlist<String> list = new Linkedlist<>();
list.put("Maria");
list.put("Ales");
list.put("zina");
list.put("bina");
list.put("fina");
list.remove("zina");
Some issues:
Your code is too optimistic. There are several boundary cases you should check for null values.
The code blocks that deal with a match of the first or last node, rewire the wrong node.
The size value is not adjusted when the first or last node is removed
When no match is found, size is still decremented.
Corrected version with comments:
public void remove(T e) {
if (first == null) {
throw new IndexOutOfBoundsException("List is empty");
}
if (first.item.equals(e)) {
first = first.next;
// first can be null now!
if (first != null) {
// As you already moved the `first` reference, you should not go to next:
first.prev = null;
}
} else if (last.item.equals(e)) { // make this an else if
last = last.prev;
// As you already moved the `last` reference, you should not go to prev:
last.next = null;
} else {
Node<T> current = first.next; // can go to next here already
// avoid current to be null, so make it the loop condition
while (current) {
if (current.item.equals(e)) {
current.prev.next = current.next;
current.next.prev = current.prev;
// No need to continue. Just exit here
break;
}
current = current.next;
}
if (current == null) return; // Not found! We should not decrement the size
}
// Size must be decremented here, since it also applies to head/tail removals!
size--;
System.out.println("Removed");
}
Remarks:
After last = last.prev; we can be sure that last is not null. If it were, then the original value of last was equal to first, and then we would never have gotten here.
In the if (current.item.equals(e)) { block, we can be sure that both current.prev and current.next are not null. If they would have been, then current would represent the first/last node, for which we had already concluded that they were not a match.
I assumed that all nodes are guaranteed to have an item property.
I assumed that at most one node should be removed
Related
Can anyone help on what's wrong with my code? Only the first input number shows up when I run it (it doesn't create a sorted list), the delete command isn't working, and the 'true' 'false' in exists command doesn't show up. My output should match the given sample I put at the end.
The areas I had to fill in to make the code work are the areas after the TODOTODOTODO symbols which would be 44-61, 75-83, 97-105. I'm not sure where I went wrong in those areas and why it is not working correctly to give the desired output?
import java.util.Scanner;
// Defines the a Sorted Set collection and implements a driver program in main
public class SortedSet {
// Define a basic element of a linked list
private class LinkedNode {
int x; // Value stored in the node
LinkedNode next; // Reference to the next node in the list
}
LinkedNode front = null; // Reference to the front of the singly linked list
// Adds the integer x to the collection.
// The resulting collection is sorted in increasing order and
// does not contain any duplicate values.
public void add(int x) {
// Initialize a new node to be added to the collection
LinkedNode newNode = new LinkedNode();
LinkedNode cur = front;
newNode.x = x;
// Check if list is empty
if (cur == null) {
front = newNode;
}
// If list is not empty, check if node should be placed in front
else if (front != null) {
if (newNode.x < front.x) {
newNode.next = front;
front = newNode;
}
// If not in front, check for the middle or the end, or duplicate.
else {
// <TODO><TODO><TODO>
LinkedNode temp = cur;
LinkedNode prev = cur;
int middle = x;
while (temp != null) {
if(temp.x > newNode.x) {
middle = 1;
newNode.next = temp;
prev.next = newNode;
}
prev = temp;
temp = temp.next;
}
if (middle == 0) {
prev = newNode;
}
}
}
}
// Deletes the integer x from the sorted set.
// The remaining collection remains sorted and without duplicates.
public void delete(int x){
// Declare a new reference and initialize it to the front of the list
LinkedNode cur = front;
// Check if list is empty
if (front == null) {
System.out.print("There is nothing to delete!");
} else { // Not empty
// Go through list, checking whether node is in the list, and delete if found
// <TODO><TODO><TODO>
LinkedNode prev = new LinkedNode();
while (cur.x != x && cur != null) {
prev = cur;
cur = cur.next;
}
if (cur != null)
prev.next = cur.next;
}
}
// Returns true if the integer x exists in the sorted set and false otherwise.
public void exists(int x) {
// Declare a new reference and initialize it to the front of the list
LinkedNode cur = front;
// Check if list is empty.
if (front == null) {
System.out.println("false");
}
// If not empty, check for the node.
// <TODO><TODO><TODO>
else {
while (cur != null) {
if (cur.x==x)
return;
cur=cur.next;
}
return;
}
}
// Returns a string representing the sorted set as a space separated list.
public String toString() {
String s = "";
LinkedNode cur = front;
while (cur!=null) {
s+= cur.x + " ";
cur = cur.next;
}
return s;
}
// Driver method
public static void main(String[] args) {
// Declare variables
SortedSet sortedSet = new SortedSet();
Scanner scan = new Scanner(System.in);
String[] tokens;
String command;
int num;
// Print header info
System.out.println("Programming Fundamentals\n"
+ "NAME: Andres Reyes\n"
+ "PROGRAMMING ASSIGNMENT 4\n");
// Enter command loop
while (true) {
// Prompt the user for a command
System.out.print("Enter command: ");
String input = scan.nextLine();
// Parse input
if (input.equals("q")) break; // user quits
tokens = input.split("\\s");
if (tokens.length < 2) continue; // invalid input
command = tokens[0];
num = Integer.parseInt(tokens[1]);
// Execute command
if (command.equals("add")){
sortedSet.add(num);
System.out.println(sortedSet);
} else if (command.equals("del")) {
sortedSet.delete(num);
System.out.println(sortedSet);
} else if (command.equals("exists")) {
sortedSet.exists(num);
} else {
System.out.print("Command does not exist");
}
}
System.out.println("\nGood bye!");
}
}
I made following changes in the add-function and they got it working for me:
// If not in front, check for the middle or the end, or duplicate.
else {
// <TODO><TODO><TODO>
LinkedNode temp = cur.next; // start at cur.next as your temp-variable
LinkedNode prev = cur;
int middle = 0; // set middle to 0
while (temp != null) {
if(temp.x > newNode.x) {
middle = 1;
newNode.next = temp;
prev.next = newNode;
}
prev = temp;
temp = temp.next;
}
if (middle == 0) {
// add node to the end
prev.next = newNode;
}
}
}
You have to start at cur.next as your temp-variable.
As far as I can see, you're not yet checking if there are any duplicate values in your list.
Edit: I didn't work on the exists-method, which is not giving you any output at the moment. The problem is simply that you're generating any output while you're checking if a value exists in your list. You could either write a System.out.print which prints "true" in case the value was found or "false" in case if wasn't. Or you change the return type of the exists-function to boolean, return a boolean according to the result and print the return value.
It might also help you to visualize a linked list to unterstand why you have to change the temp-variable to cur.next. I think https://www.tutorialspoint.com/data_structures_algorithms/linked_lists_algorithm.htm gives a good explaination of the insertion process.
I can give you some hints. The main problem I see with this code is that you really need a reference to the start of the LinkedList (the head) would be the only way to print the list and check for duplicates.
The following should be added to your class
LinkedList head = null; //start of the list
Then you have to update your toString() or you will never print the correct elements in your list no matter what you do. Try this:
public String toString(){
StringBuilder output = new StringBuilder();
LinkedNode current = head;
while(current != null){
output.append(current.x).append(" ");
current = current.next;
}
return output.toString();
}
You have to be really careful when you are appending to a String in a loop because Strings are immutable. Everytime you are appending to a list you are creating a new String. Instead, use StringBuilder.
//s+= cur.x + " ";
Your add method should handle the following cases:
Case 1: List is empty: ( don't forget to set ref to head)
Case 2: new element is great than front of list
Case 3: new element is less than current head
Case 4: new element is less than current and greater than head
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!
I've been struggling to figure out why this code is stuck in an infinite loop. The back story is I have found the solution, I changed the constructor to assign head is equal to null and that fixed it.
I wonder why this code is NOT working.
When I add different nodes, it is working. The code works as expected.
Issues arise when adding the same node.
public class Main {
public static void main(String[] args) {
Node one = new Node(1);
Node two = new Node(2);
LinkedList list = new LinkedList(one);
// this gives error, if i add the same nodes
list.add(two);
list.add(two);
System.out.println("Printing out:\n" + list.toString() +"\n");
}
}
public class LinkedList {
Node head;
int length = 0;
public boolean isEmpty() {
return (head==null);
}
public String toString() {
Node current = head;
String string = "Head: ";
while(current.next != null) {
string += current.toString() + " --> ";
current = current.next;
}
string += current.toString() + " --> " + current.next;
return string;
}
public LinkedList(Node node) {
// if were to set head to null and no arg, it works fine
head = node;
length = 1;
}
public void add(Node node) {
if(isEmpty()) {
System.out.println("Empty list, adding node...");
head = new Node(node.data); ++length;
return;
}
else {
Node current = head;
while(current.next != null) {
current = current.next;
}
//current.next = new Node(node.data);
current.next = node;
++length;
return;
}
}
The error is, it never terminates, hence why I think it is forever looping.
I think in your add(Node node) code. When you adding same node twice, it will point the next to itself. Therefore it would be infinite loop.
Its going in infinte loop because of while loop in toString() method of LinkedList class.
you are validating on condition
while(current.next != null) { .....}
after reaching on last node, you are not setting next of last node to null, so the condition will never terminate.
To resolve this where you are adding node point node.next = null;
current.next = node;
node.next = null;
++length;
return;
It will terminate and will not go in infinte loop
The line in your code not fine is in add method ‘current.next=node’ . Try to change it to ‘current.next=new Node(node.data)’
I believe I have the code on how to remove an item in a linked list but I'm not sure how I can make it so that all occurrences of a value would be removed. Where would I need to make some changes that would have it check through all the values in the list?
I've tried to make an alternate or a dummy that pointed to the head but I wasn't sure where I was going with that.
public class LinkList {
private Link first; // ref to first link on list
// -------------------------------------------------------------
public LinkList() // constructor
{
first = null; // no links on list yet
}
// -------------------------------------------------------------
public void insertFirst(int id, double dd) {
Link newLink = new Link(id, dd);
newLink.next = first; // it points to old first link
first = newLink; // now first points to this
}
// -------------------------------------------------------------
public Link find(int key) // find link with given key
{ // (assumes non-empty list)
Link current = first; // start at 'first'
while (current.iData != key) // while no match,
{
if (current.next == null) // if end of list,
{
return null; // didn't find it
} else // not end of list,
{
current = current.next; // go to next link
}
}
return current; // found it
}
// -------------------------------------------------------------
public void displayList() // display the list
{
System.out.print("List (first-->last): ");
Link current = first; // start at beginning of list
while (current != null) // until end of list,
{
current.displayLink(); // print data
current = current.next; // move to next link
}
System.out.println("");
}
// -------------------------------------------------------------
public Link removeAll(int n) // delete link with given key
{ // (assumes non-empty list)
Link current = first; // search for link
Link previous = first;
while (current.iData != n) {
if (current.next == null) {
return null; // didn't find it
} else {
previous = current; // go to next link
current = current.next;
}
}
if (current == first) // if first link,
{
first = first.next; // change first
} else // otherwise,
{
previous.next = current.next; // bypass it
}
return current;
}
}
I expect to have all the values deleted for a given key but it I'm only able to delete one instance of a given value.
This removes all occurrences of Link with id == n. It should be the same if you want to remove by Link.iData.
public Link removeAll(int n)
{
Link head = first;
Link previous = null;
Link current = first;
while (current != null) {
if (current.id == n) {
if (previous == null) {
head = current.next;
} else {
previous.next = current.next;
}
} else {
previous = current; // if we removed current, let previous remain the same
}
current = current.next;
}
first = head;
return head;
}
Running the code like this:
LinkList l = new LinkList();
l.insertFirst(0, 0.1);
l.insertFirst(3, 3.1);
l.insertFirst(1, 1.1);
l.insertFirst(3, 3.1);
l.insertFirst(2, 2.1);
l.displayList();
l.removeAll(3);
l.displayList();
Outputs:
List (first-->last):
2 : 2.1
3 : 3.1
1 : 1.1
3 : 3.1
0 : 0.1
List (first-->last):
2 : 2.1
1 : 1.1
0 : 0.1
I have this class called ListNode, similar to yours.
public class ListNode {
public ListNode next;
public int val;
public ListNode removeAll(int n) {
ListNode newHead = null;
ListNode node = this;
//for keeping track of the node previous to the current node
ListNode prev = null;
//loop through the entire linked list
while (node != null) {
//when you encounter the val == n, delete the node
if (node.val == n) {
if (prev != null){
//this makes the previous node to point the node to the next of the current node
//if 2 -> 1 -> 3 and we have to remove node with key 1 and current node val == 1
// the following code will do this
// 2 -> 3
prev.next = node.next;
}
ListNode next = node.next;
//taking the same example
//this code will break the link : 1->3
node.next = null;
node = next;
} else {
if (newHead == null) {
newHead = node;
}
prev = node;
node = node.next;
}
}
return newHead;
}
}
You, basically, have to traverse through whole linked list, keeping track of the previous node for the current node and when you find a node with value/key/data equal to n, you make the previous node point to the next node of the current node and break the link of the current node to the next node.
Let's first start without deleting anything. To delete all occurrences, you first need to be able to iterate over the entire list (so you can look for multiple matches). Iterating over the whole list would simply be:
public void removeAll(int n) // delete link with given key
{
Link current = first;
Link previous = first;
while (current != null)
{
// simply move to the next Link
previous = current; // store the current node as the previous for the next iteration
current = current.next; // move to the next link
}
}
Next, let's add in a check to see if the current Link is one that should be deleted:
public void removeAll(int n) // delete link with given key
{
Link current = first;
Link previous = first;
while (current != null)
{
if (current.iData == n)
{
// To do...delete the current Link
}
else
{
// simply move to the next Link
previous = current; // store the current node as the previous for the next iteration
current = current.next; // move to the next link
}
}
}
Once we've found a match, there are two possibilities. Either the Link is the first Link, or it is somewhere further down in the list:
If the link is the first one, then we move current to the next Link, and make both first and previous point to the new current Link.
If we are not the first Link, then we move current to the next Link, and update the previous.next field to point to the new current Link (thus skipping over the Link to delete).
Here's the updated code:
public void removeAll(int n) // delete link with given key
{
Link current = first;
Link previous = first;
while (current != null)
{
if (current.iData == n)
{
if (current == first)
{
current = current.next;
first = current;
previous = current;
}
else
{
current = current.next;
previous.next = current;
}
}
else
{
// simply move to the next Link
previous = current;
current = current.next;
}
}
}
Here is simple recursive implementation (this implementation leaves initial list intact, and creates new without specified element):
public class Answer {
public static void main(String[] args) {
LinkedList list = new LinkedList(1, new LinkedList(2, new LinkedList(1, new LinkedList(2, new LinkedList(3, null)))));
System.out.println(list);
LinkedList withoutOne = list.removeAll(1);
System.out.println(withoutOne);
LinkedList withoutTwo = list.removeAll(2);
System.out.println(withoutTwo);
LinkedList withoutThree = list.removeAll(3);
System.out.println(withoutThree);
}
}
class LinkedList {
private int value;
private LinkedList next;
public LinkedList(int value, LinkedList next) {
this.value = value;
this.next = next;
}
public LinkedList removeAll(int value) {
if (this.next == null) {
return (this.value == value) ? null : new LinkedList(this.value, null);
} else if (this.value == value) {
return this.next.removeAll(value);
} else {
return new LinkedList(this.value, this.next.removeAll(value));
}
}
#Override
public String toString() {
String res = "LinkedList:";
for (LinkedList link = this; link != null; link = link.next) {
res += " " + link.value;
}
return res;
}
}
Hi im trying to remove a link in part of a linked list but i'm not sure how to remove the link. when i run it the links are still there. im using a junit to test the function if that matters .
Here is what i have so far.
public void removeAt(int k)
{
Node w = first;
int counter = 0;
if (k<0 || k >= size())
{
throw new IndexOutOfBoundsException("Error ");
}
else
{
while (w!= null)
{
counter++;
if (counter == k)
{
Node now = w.next;
w= now.next;
}
w=w.next;
}
}
assert check();
}
Thanks for the help
You need to change a node's .next field in order to remove a node, e.g. w.next = w.next.next removes the w.next node from the list (because nothing is pointing to it anymore); be sure to check for null pointers (if w.next is null then w.next.next will throw an exception). Also, add a break statement to the end of your if block since there's no need to traverse the rest of the list.
if (counter == k){
Node now = w.next;
w.next= now.next;
break;
}
test this.
You are updating a local variable. What you need to do is update the link prior to the current node:
if (k == 0)
{
first = first.next ;
// you also have to free the memory for first.
}
else
{
Node Last = first ;
w = first.next ;
counter = 1 ;
while (w!= null)
{
counter++; // Not sure your conventions, but I think this should be at the end
if (counter == k)
{
last.next = w.next ; /// happily skipping w :)
// remember you have to free w
break ; // no point in continuing to the end.
}
w=w.next;
}
}
}
You always need to keep track of the previous node. And also what if the node that's to be deleted is the first node? I guess you need to change the while block to look something like:
Node l = first;
while (w!= null)
{
if (counter == k)
{
if (w == first)
first = w.next;
else
l.next = w.next;
w.next = null;
break;
}
l=w;
w=w.next;
counter++;
}
Check the following code that remove the element from linked list,
public void delete(T element){
if(head != null){ // first check your header node is null or not
// create two references of your linked list
Node<T> tmp = head; // it will hold current value
Node<T> tmp1 = head.getNextRef(); // it will hold next value
while(true){ // iterate through whole linked list
if(head.getValue() == element){ // if you found element at first place
head = head.getNextRef(); // then point head to next node of it
break;
}
if(tmp1.getValue()==element){ // to remove node refer to next of tmp1
tmp.setNextRef(tmp1.getNextRef());
break;
}else{
tmp = tmp1;
tmp1 = tmp1.getNextRef();
if(tmp1==null)
break;
}
}
}
}