folks, my code has to remove a certain element from the list. It has to remove all of the occurences of the list. For example, if I'd like to remove "3" and the input is:
1
2
3
4
3
5
then the output should be:
1
2
4
5
But my code only removes the last occurence of the element as it can be seen when I run my code:
3
4
3
2
1
After removing element 3
4
3
2
1
Could smb please help me out with that? THanks in advance!
public void removeElements(String number){
if(isEmpty()){
System.out.println("The list is empty!");
}
else{
if(firstLink.data.equals(number)){
firstLink = firstLink.next;
}
else{
Link current = firstLink.next;
Link previous = firstLink;
while(current != null){
if(current.data.equals(number)){
previous.next = current.next;
break;
}
else{
previous = current;
current = current.next;
}
}
}
}
}
Your loop to remove elements is breaking on the first match. Maybe something like the following would work better. When current is a match, update previous.next but leave previous pointing at the previous node, and when it's not a match, update previous to point to the current node.
while (current != null) {
if (current.data.equals(number)) previous.next = current.next;
else previous = current;
current = current.next;
}
Remove the break, your loop is breaking after it gets into it for the first time.
Another point is, it is falling in your if(firstLink.data.equals(number)) and completely ignoring the else block. You should not have that block in else. It should be outside.
if(firstLink.data.equals(number)){
firstLink = firstLink.next;
}
Link current = firstLink.next;
Link previous = firstLink;
while(current != null){
if(current.data.equals(number)){
previous.next = current.next;
} else {
previous = current;
current = current.next;
}
}
What you can do is iterate through the entire loop and check if the value of the element matches the searched value. If it does then you can use remove that element. I won't give away the solution to this but I can provide you with the algorithm.
for(int i = 0; i < length of list; i++)
{
if(ith element of the list == value to be removed)
//remove the ith term using .remove(i) method
}
What you could do is make a new collection containing all the values you want to remove from the LinkedList, and then call removeAll on the list:
ArrayList<String> numbersToRemove = new ArrayList<String>();
numbersToRemove.add("3");
list.removeAll(numbersToRemove);
This way, if you want to remove multiple numbers later on, you can just add them to numbersToRemove.
Some of the other answers are a bit simpler and more straightforward, though, so use them if they make sense, like iterating through the list and removing any elements that match the element you are removing. The only problem with this is that you will get a ConcurrentModificationException if you modify the list while iterating through the list using the object : list syntax, and will probably get an index out of range exception if you iterate through it using indices, so you will probably need to do something like this instead:
while (list.contains("3")) {
ll.remove("3");
}
Related
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 3 years ago.
I have a complete working method to reverse a doubly linked list. To be honest I've been going back and fourth for months trying to trace this code to see exactly how it works but I get confused at the end of the while look when I update my current node with current.prev
Ive tried to print out the values of the nodes for each time it changes the next and previous pointers however I get a nullpointerexception, so no luck there.
public void reverse(){
Node temp = null;
Node current = head;
while(current != null){
temp = current.prev;
current.prev = current.next;
current.next = temp;
current = current.prev;
}
if(temp != null){
head = temp.prev;
}
}
There are no errors here, I passed it thru my own test cases for the worst and best scenario. I just can't seem to understand what is going on. I know this is essentially swapping the next and prev pointers but I need to know how.
public void reverse(){
// Create initial values
Node temp = null;
// Note that you are using current to traverse through the linked list
Node current = head;
// While current is not at the end of the original (non-reversed) list
while(current != null){
// Swapping prev and next
temp = current.prev; // temp 'temporarily' holds copy of current.prev
current.prev = current.next; // current.prev is overwritten with current.next
current.next = temp; // current.next is overwritten with temp (containing original current.prev)
// You are setting current to the newly redefined prev
// This was equal to current->next in the original (non-reversed) list
// So you are traversing through the original list
// Anything 'before' this has already been reversed
// Anything 'after' still needs to be reversed
current = current.prev;
}
// Condition checks for edge case of a one node linked list
if(temp != null){
// Set the head of the reversed list
head = temp.prev;
}
Commented code above. I'm not a Java programmer, but in C I would print out the addresses of each node before and after the reversal to check I am doing things properly. Perhaps, you can use hashcodes to do something similar?
This is similar to a swap in Java:
while(current != null){
temp = current.prev; //gets the 'end' of the doubly linked list
current.prev = current.next; //sets the 'end' of the doubly linked list to the 'first' of the list
current.next = temp; //sets the 'first' of the list to temp, which is the 'end' of the list
current = current.prev; //iterate through the list in reverse order (similar to i++ in for loops)
}
if(temp != null){
head = temp.prev; //edge case when there is only 1 node.
}
This Code below is from a java LinkedList implementation.The method adds a string element at an index point of the list and is taken from one of my cs books.
The linked list class has 2 global private variables
Node first;
Node last;
public void add(int index, String e) {
if (index < 0 || index > size()) {
String message = String.valueOf(index);
throw new IndexOutOfBoundsException(message);
}
// Index is at least 0
if (index == 0) {
// New element goes at beginning
first = new Node(e, first);
System.out.println("ran");
if (last == null)
last = first;
return;
}
// Set a reference pred to point to the node that
// will be the predecessor of the new node
Node pred = first;
for (int k = 1; k <= index - 1; k++) {
pred = pred.next;
}
// Splice in a node containing the new element
pred.next = new Node(e, pred.next);
System.out.println(toString());
// Is there a new last element ?
if (pred.next.next == null)
System.out.println("ran");
last = pred.next;
}
My question
I don't understand how Node first, last get updated in the condition below
Suppose you have a list that looks like ["1","2","3","7","4","5,"6"]
Then you add the the element "4" to index 3
So, the list looks likes ["1","2","3","4","7","4","5,"6"], but looking at the code of the add method I don't know how the first or last node pointers gets updated. Because in my mind these are the only pieces of code that run because the index isn't 0 and the last doesn't change
EDIT
The Object Node first is used in the toString method(not shown) to traverse through the collection
// Set a reference pred to point to the node that
// will be the predecessor of the new node
Node pred = first;
for (int k = 1; k <= index - 1; k++) {
pred = pred.next;
}
// Splice in a node containing the new element
pred.next = new Node(e, pred.next);
System.out.println(toString());
Before the add, the first element is "1" and the last element is "6".
After the add, the first element is "1" and the last element is "6".
You're right that the first and last dont change-- they don't need to, because you haven't changed the first or the last element.
I think you are getting bogged down by the way this linked list implementation works. The first and last pointers exist to just keep track of the start and end of the list. Hence, when you insert an element in the middle of the list, these pointers do not get updated, nor is there any need for such an update. But they do get updated should an insert land before the current head or after the current tail of the list. Here is the code which handles head inserts:
if (index == 0) {
// New element goes at beginning
first = new Node(e, first);
System.out.println("ran");
if (last == null)
last = first;
return;
}
The critical line here is actually this:
first = new Node(e, first);
The first pointer gets assigned to a new node, which in turn points to the old first node. Similarly, should an insert of a new node land at the end of the list, the following code will handle that:
if (pred.next.next == null) {
System.out.println("ran");
last = pred.next;
}
Here the last pointer is assigned to the new node which was inserted after the old last.
But other than these two edge cases, there is no need to update first and last with inserts.
If the index is 0, the node is added in the beginnng and the for loop doesn’t work.
If it is 1, the loop again doesn’t execute and node is simply added to the list.
However if it something else, then until the index-1 position is reached the loop shifts each element one step behind. Then the code just outside the loop (which slices in a node containing new element) inserts the element at index.
If after the loop has executed, the index turns out to be the last one then the last node is updated.
Hope this helps!
Clarification: The main question is which node is something like current.previous.next = current.next actually pointing to?
I'm using some sample code I found on a YouTube video, but really trying to break it down and understand it. Everything works as-is, I've added comments to each section to help me understand. Where I am really running into problems explaining what is happening in plain English is for node removal when the code start using previous and next in the same line. I'm not following exactly what it's pointing to now. I've worked through the code in the debugger, but I need some plain English explanation if someone wouldn't mind.
Let's say for example I've got a DLL that has 3,4,5,6,7. So I'm going to remove 5, which is the 3rd index. Here is the method for removal.
//Method to remove node at a specified position
public void removeAt(int index) {
//If the head doesn't exist, break out of the logic
if(head == null) return;
//If the requested index is smaller than 1 or greater
//than the size of the list, break out.
if(index < 1 || index > size) return;
//Declares the currently used link as the head
Link current = head;
//Declare int i counter for use in while loop
//While i is less than the index set current to the next node
//and add to the counter i
int i = 1;
while(i < index) {
current = current.next;
i++;
}
//If the next node doesn't exist, set current...previous next?
if(current.next == null) {
current.previous.next = null;
}
//Else if the node before the current is null, set current to
//the next node and then set the previous to null (I thought it
//already was null??) Set the head to the current node
else if(current.previous == null) {
current = current.next;
current.previous = null;
head = current;
}
//If none of the above conditions, set current previous next?? to
//the next node and current next previous to the previous node??
else {
current.previous.next = current.next;
current.next.previous = current.previous;
}
//Subtract from the size of the list
size--;
}
My main understanding issues come in when it starts using current.previous.next and current.next.previous. To me, current.previous.next is just saying to remain at current. If I have three numbers, 3 4 5 and current is 4, then previous is 3, so next would just go back to 4. I know this isn't right, but after reading other posts here, the Javadoc, and watching videos, I'm still not understanding what is going on.
Here is the other class:
public class Link {
private int data;
public Link previous;
public Link next;
public Link(int data) {
previous = null;
this.data = data;
next = null;
}
public Link(Link previous, int data, Link next) {
this.previous = previous;
this.data = data;
this.next = next;
}
public int Data() {
return data;
}
}
I'd appreciate some explanation. Thanks!
If node.next is null, it means that the node is the last element of the list. So if you try to remove the last element of the list, the element before the last element becomes the last element. Which is what this code does
if(current.next == null) {
current.previous.next = null;
}
If node.previous is null, it means that it is the first element of the list. First, we have to keep a reference to the following element, define that the following element must not have a previous element, and then define it as the head of the list. Which is what this code does
if(current.previous == null) {
current = current.next;
current.previous = null;
head = current;
}
Then to stay on your example
if current is 4, then current.previous is 3 and current.next is 5
so
current.previous.next = current.next
define that 3.next is now 5
and
current.next.previous = current.previous
define the 5.previous is now 3
So then 4 is not reference anymore in the list
Doubly link list (DLL) is a list that can be traversed in both directions as you already know. Each node has previous and next pointers to their siblings allowing navigation to both directions. You already have head variable pointing to the head of the linked list.
In the remove method you passed in the index of the node you wish to delete.
while(i < index) {
current = current.next;
i++;
}
Above while loop sets the current node to be the node we wish to delete. There are three cases to be handled at this point.
Current node can be the first node in the list. So current.previous points to nothing and current.next may point to next node if there is one.
Current node can be the last node of the list so that current.next = null.
Current node is neither head or tail of the list so that current.next and current.previous have corresponding values.
if(current.next == null) {
current.previous.next = null;
}
Above code section will is the second point mentioned above. current points to last node. In order to remove last node you have to go back to current.previous and set its link to null so that current will no longer be accessible from the previous node.
else if(current.previous == null) {
current = current.next;
current.previous = null;
head = current;
}
checks to see if the current node is the head of the node. If current is pointing to head of the linked list, it does not have any previous sibling so that current.previous points to null. So current.next must become the new head of the list. With current.previous = null we set the previous link to null and set this current head as the head variable. Now previous node has gone. No references to it.
Third case is the above bullet point 3. It's handled by
else {
current.previous.next = current.next;
current.next.previous = current.previous;
}
where we want to remove current node. That means we need to link current.previous and current.next as siblings.
As a final note, your Link class uses public fields. They should be private and access via getters and setters.
So I'm trying to delete an item from a linked list in java.I'm not using java's predefined LL but I'm working with my own.
I know the concept to delete an item is to traverse in the link and compare the data in the list one by one.
so here's what I came up with, but it doesn't work!
public void delStudent(int regN) {
Node current = head;
Node q = head;
if (current.getStudent().getRegN() == regN) {
head = head.link;
}
for (int i = 0; i < this.length() - 1; i++) {
if (current.getStudent().getRegN() != regN) {
current = current.link;
q = current;
}
}
q.link= current.link.link;
}
Well, if your list is empty, the execution of the if statement in the beginning will immediately give a NullPointerException (because current will be null). Generally, for the LinkedList delete method, you must consider three cases: size == 0, size == 1, and size > 1 (where size is the number of nodes in the Linked List).
public void delStudent(int regN) {
Node current = head;
Node previous = head;
while (current != null ){ // keep traversing till end of list
if (current.getStudent().getRegN() == regN) { // found it!
previous.link = current.link; // relink
if (current == head){ // edge case : removed first element
head = current.link; // move head forward.
}
break;
} else {
previous = current;
current = current.link;
}
}
}
The above code assumes regN is unique and that there is only one student with that regN. Hope this helps.
The mistake is (I think) in these three lines:
current = current.link;
q = current;
(where you set q to be the same as current) and
q.link= current.link.link;
(and maybe also in using length() depending on it's implementation)
To see why let's look at how to delete in more detail:
Let's consider there are three nodes in your list x->y->z and you want to delete y.
In order to do so you need to set x.link = z.
To return to you example it means that the variable q should store the element before current, then deleting current can be done by
q.link = current.link;
In order order to have q be the predecessor of current you have to reverse the two lines above, i.e., use
q = current;
current = current.link;
Why am I saying depending on the implementation of length ? If you implementation of length just returns some number maintained by increasing whenever you add a value to the list, you should also decrement it when deleting one. If length traverses the list in order to find the number of elements then its ok, although not very efficient.
One last comment: your code will not work (even with the fixes I explain above) when there is no element with the given regN. Why? Because you always delete one element. Moreover, you might want to rethink the logic inside the loop. Currently if the element to delete is the second one and there is 1000000 elements you will run the loop nearly 1000000 times.
When you are checking each node you need to delete the node or break once you find a match. You need to maintain a node for the previous node to be able to delete the current node once you find a match.
I just realized that you were attempting to to that with Node q
for (int i = 0; i < this.length() - 1; i++) {
if (current.getStudent().getRegN() != regN) {
q = current;
current = current.link;
} else{ //we have a match
//remove the link to the current item
q.link = current.link;
break;
}
if you are using a doubly linked list you can use node.prev().link = current.link;
I am attempting to write code that will remove the duplicate nodes in a singly-linked list. The duplicates removed are only removed until the number stored in the next node changes.
For example, if the input list is [ 0 0 0 0 1 1 0 0 0 3 3 3 1 1 0 ],
the output list is [ 0 1 0 3 1 0 ].
I have attempted to write the code and tried multiple things. Each time when I call the function it either returns the original linked list or just the original head and original tail.
I attempted creating a temporary linked list and storing values in that list but it does not return properly.
My latest attempt is in the code snippet below and only returns the head and tail of the original list.
My question is, how I should proceed with this code? I tried to draw it out and visualize it but it did not help.
I am not looking for code to be written just a push in the correct direction.
I think that the code I have now is a dead end and I may have to restart from scratch.
What is the best way to start to implement this code to achieve an answer?
public void squish() {
SListNode current = head;
SListNode iterator = current.next;
while (iterator != null){
if (current.equals(iterator)){
iterator = iterator.next;
} else {
if (current.next.equals (null)) {
break;
} else {
head.next = iterator;
current = iterator;
}
}
}
}
In your current solution you are trying to do 2 things at once, skipping n equal numbers and re-arranging your list. This makes the solution a bit more complex than necessary.
What you can do is looping while you have a current node and that current node is followed by another.
now within the loop you have 2 possibilities;
either the values of current and next are equal, in that case make the node following current (next) the same as the one following the current next.
or the values are unequal, in that case walk the list by setting the current node to its follower node.
That's it, no explicit assignments to the head reference should be necessary.
I'm guessing that this is homework, so I don't want to give a complete solution.
Working directly with iterators is always tricky. Instead of working in place with a single List, you should consider creating a new List with the solution you want. e.g., schematically...
Create a new empty List for the result
Initialize prevValue
Loop over the values in input list
If the value is not equal to the prevValue
add it to the result list
update prev value
Of course, if the class/assignment really wants you to use iterators, ignore the above...
public void RemoveDuplicates()
{
Dictionary<int, int> myDict = new Dictionary<int, int>();
Node cur = head;
myDict.Add(head.Data, 1);
while (cur.Next != null)
{
if (myDict.ContainsKey(cur.Next.Data))
cur.Next = cur.Next.Next;
else
{
myDict.Add(cur.Next.Data, 1);
cur = cur.Next;
}
}
}