public void deleteItem(int target)
{
int index = 0;
CarNode item = head;
while(item != null)
{
CarNode next = (item.node).node;
CarNode previous = item;
if (index == target)
{
previous.setNode(next);
}
item = element.node
index++;
}
}
Yeah, I don't know if I understood well, but I got told that you can use reference and don't have to directly refer to an object of the linked list in order to perform changes on the linked list.
A node contains the Car object and the node of another element of the LinkedList, right, so the reference is basically a clone that points to the same object as the original, but how come that the original is ignored and the reference takes precedence over the original when we modify the node of the reference? Sorry, it didn't make any sense to me and I've been scratching my head for hours over this.
The code should look like this:
public void deleteItem(int target)
{
int index = 0;
CarNode item = head;
CarNode prev = null;
while(item != null)
{
if (index == target) {
if (prev == null) {
head = item.getNode();
return; // We've removed the target.
} else {
prev.setNode(item.getNode());
return; // We've removed the target.
}
}
prev = item;
item = item.getNode();
index++;
}
}
So let's break this down:
int index = 0;
CarNode item = head;
CarNode prev = null;
We need two variables: one to store the element we're looking at, the other to store the previous element (which we will use to reconnect the list once we remove an element). To start, our current is the head, and our previous doesn't exist. index will let us know when we reach the target.
while(item != null)
We want to iterate until we've hit the end of the list, marked by a null node.
if (index == target) {
if (prev == null) {
head = item.getNode();
return; // We've removed the target.
} else {
prev.setNode(item.getNode());
return; // We've removed the target.
}
}
If we've found the target, we remove it. If previous is null, then the target was the head, so we move the head to the 2nd element. Otherwise, we make the previous node's reference to be the current node's reference, which cuts the current node out of the list. Once we remove the target, we are done, so we return.
prev = item;
item = item.getNode();
index++;
Update the previous and current nodes. Both are moved forward one node. Index is incremented.
How about an illustrated example:
Take a list of size 3. It looks like this:
We now call list.deleteItem(1); This instantiates a prev and a next node. next points to the first node, and prev is null.
Our target is 1, so we move to the next node. Now prev points to what next used to point to, and next points to the 2nd object in the list (the one we want to remove).
We remove it by setting the prev node's reference to be the next node's reference.
When we return from the method, java garbage collection does its job, and we're left with:
Tada! Node removed from the list!
public void deleteItem(int target)
{
int index = 0;
CarNode item = head;
CarNode next = null;
CarNode previous = null;
// stop when the linked-list ends
while(item != null)
{
// the tail has no next node
if (item.node != null)
next = item.node.node;
else
next = null;
// if targetIndex exist, remove it
// "logically" from the linekd-list
if (index == target)
{
previous.setNode(next);
break;
}
// today is tomorrow's yesterday
previous = item;
item = item.node;
index++;
}
}
Related
I have a method that adds elements into a doubly linked list, and swaps elements into ascending order if the first element is greater than the second element. If I input 23, 24, 16, it skips swapping 23 and 24 because those are good, and then it swaps 23 and 16 fine. Then when it goes back into the for loop I get an error saying that first.getNext() is null. I can see that next is getting lost in the swapping, and I tried wrestling with some fixes but have not been able to get it right.
#Override
public void add(T element) throws NullPointerException{
DoubleLinearNode<T> newNode = new DoubleLinearNode<T>(element); // Calls constructor to create a new node with data set to parameter.
if(element == null)
throw new NullPointerException("Cannot add a null element"); // Throws exception when parameter is null.
if(isEmpty()) { // Add a single node.
head = newNode;
tail = newNode;
count++;
modChange++;
}
else { // Add node to the back.
tail.setNext(newNode);
newNode.setPrevious(tail);
tail = newNode;
count++;
modChange++;
}
//}
DoubleLinearNode<T> hold = null;
DoubleLinearNode<T> first = null; // First element in list.
DoubleLinearNode<T> second = null; // Second element in list.
if(size() > 1) { // If there are 2 elements to compare then swap.
for(first = head; first.getNext() != null; first = first.getNext()) {
for(second = first.getNext(); second != null; second = second.getNext()) {
if(first.getData().compareTo(second.getData()) > 0) {
hold = first;
first = second;
second = hold;
System.out.println(first.getData());
System.out.println(second.getData());
}
}
}
}
}
I tried using this code to swap nodes but then I get an error saying that hold is null.
hold.setData(first.getData());
first.setData(second.getData());
second.setData(hold.getData());
Something like this might work. As mentioned in the comments, you do not need to swap, just find the insertion point and relink from both sides:
#Override
public void add(T element) {
DoubleLinearNode<T> newNode = new DoubleLinearNode<>(element);
if (element == null)
throw new UnsupportedOperationException("Cannot add a null element");
//Add first node
if (isEmpty()) {
head = newNode;
tail = newNode;
} else {
//I would suggest to extract the following logic to
// a dedicated methods to find the insertion point and another to do the insertion
//The head needs to be replaced
if (head.getData().compareTo(newNode.getData()) > 0) {
newNode.setNext(head);
head.setPrevious(newNode);
head = newNode;
} else {
DoubleLinearNode<T> node = head.getNext();
while (node != null) {
if (node.getData().compareTo(newNode.getData()) > 0) {
DoubleLinearNode<T> previous = node.getPrevious();
newNode.setNext(node);
node.setPrevious(newNode);
previous.setNext(newNode);
newNode.setPrevious(previous);
break;
}
node = node.getNext();
}
//If no insertion point found add it to the tail
if (node == null) {
tail.setNext(newNode);
newNode.setPrevious(tail);
tail = newNode;
}
}
}
count++;
modChange++;
}
Few more notes, throws NullPointerException it's not needed at all. It is a runtime exception. It's also incorrectly used, you should throw UnsupportedOperationException or IllegalArgumentException in such cases. But is it really needed to throw an exception? It's a bad practice to control the program flow by exceptions. If I was implementing this, I would maybe just do nothing in case of null element or change the method add to return a boolean indicating whether the addition was successful or not and return false in case of null element.
You used for loops where while loop is a better fit, it works with for loop as well, but it's less readable.
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.
I'm trying to write a method that takes to elements and delete all element between them and if one of the two elements doesn't exist no element will be removed so I wrote a method but it doesn't work it's stuck in a loop , see the code :
note : 1- I can't call any method .
2- I can't use use any auxiliary data structure.
public void removeBetween(T e1, T e2) {
if (head == null) {
return;
}
Node<T> tmp1 = current;
current = head;
while (current != null) {
if (current.data.equals(e1)) {
current = head;
while (current != null) {
if (current.data.equals(e2)) {
current = head;
while (current != null) {
if (current.data.equals(e1)) {
while (current.data != e2) {
if (current == head) {
head = head.next;
} else {
Node<T> tmp = head;
while (tmp.next != current) {
tmp = tmp.next;
tmp.next = current.next;
}
if (current.next == null)
current = head;
else
current = current.next;
}
current = current.next;
}
}
current = current.next;
}
}
current = current.next;
}
}
current = current.next;
}
current = tmp1;
}
You would be better off starting from scratch. You do not need nested loops at all, let alone five levels of nesting for a task that is, essentially, linear.
Solving the task at hand has a simple plan:
First, you need to find out if the first element is present. Do it with a single while loop. If you reach the end, exit.
Store the reference to the first element in a separate variable first, and continue to finding the second element
Again, use a separate while loop. If you reach the end of the list before finding the second element, exit.
If you do find the second element, assign it to first.next.
That's it, you are done. You could do it with two consecutive while loops, or even with a single while loop and a couple of boolean variables. No nesting is necessary.
Made a code, that actually does pretty much what dasblinkenlight already stated.
Node<T> current = head; // set the current to head
do {
current = current.next; // go to next
if (current == head) { // if it's head, we have reached the end -> return
return;
}
} while (!current.data.equals(e1)); // if current.data is wrong, continue loop
Node<T> node1 = current; // match found
do { // do the same again, starting from current, to find the second node
current = current.next;
if (current == head) {
return;
}
} while (!current.data.equals(e2));
Node<T> node2 = current;
Then you can remove the elements between node1 and node2.
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
}
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.