delete node after specified node in doubly linked list. (recursively) - java

I have this recursive function that is supposed to delete the node that comes after the specified one in
a doubly linked list. However My method Isn't deleting anything. I am having trouble with rearranging the values in the list. Any ideas?
private void deleteAfterThis(T data, Node headAux) {
if(headAux == null) {
return;
}
Node deleteAfter = new Node(data);
Node target = deleteAfter.next;
if(target == null) {
return;
}
if(deleteAfter.prev == null){
if(target != tail && target==headAux) {
deleteAfter.next = target.next;
target.next.prev = deleteAfter;
size--;
deleteAfterThis(data, headAux.next);
}
else if(target == tail && target == headAux) {
deleteAfter.next = null;
deleteAfter = tail;
size--;
return;
}
}
else if(deleteAfter.prev != null) {
if(target != tail && target == headAux) {
deleteAfter.next = target.next;
target.next.prev = deleteAfter;
size--;
deleteAfterThis(data, headAux.next);
}
else if( target == tail && target == headAux) {
deleteAfter.next = null;
deleteAfter = tail;
size--;
return;
}
}
deleteAfterThis(data, headAux.next);
}

One mistake I see right off the bat is that you should not be creating a completely new node for deleteAfter. Intuitively, does it make sense to have to create a new node when attempting to delete one? I'll assume that, even knowing what the constructor for Node actually looks like, it sets the next and prev pointers to nodes to null. As a result, you'll keep recursively updating headAux until it's null without ever deleting anything. It seems what you want deleteAfter to be is headAux.next.
Another bug I see is that you've copy and pasted your checking logic twice - I recommend stepping through both cases and verifying if the logic should be identical within each block of the if and else-if blocks (it probably shouldn't).
Stepping into the logic, you should realize that the prev node of the current (headAux in your code) would be null only if headAux is the head of the list. Thus, it would be a bit more clear to rewrite the headAux.prev check as verifying if headAux is equal to the head of the linked list.
Looking at the actual deletion logic, it seems to make sense in the general case to me (assuming the fact that deleteAfter is the next node of headAux as stated above). You're making the prev of the node to be deleted to point to the deleted node's prev node and the next of the previous node (after having set the pointer, which I'm not too big of a fan of but it works) point to deleteAfter.
Lastly, when you do actually locate the node you'd like to delete, you probably shouldn't be calling the recursive function again. You already handle the setting of pointers correctly, so there shouldn't be a need to do so.
I would highly recommend you (re-)draw a sample use-case of your circular linked list and perform deletion on a sheet of paper before jumping to coding the edgecases (which aren't all handled here). The edge cases you should probably be aware of are the following: empty list, deleting head, deleting tail, single-node list. In your code, it seems that you did try to handle the deletion of the head (you'd have to remember to set the head afterwards). After getting that to work, making deletion work on other cases should be a breeze.

Related

To delete an entire linked list in java which I have created

I want to delete an entire list which I have created in java(note: I am not using internal list in java.util). I have assigned head to null but my question is will the java garbage collector handle the list which has no head or should I delete every node(I mean setting every node to null) which will be handled by java garbage collector? Following is my code, please let me know which one is ok although both works but I would still like to know. Thanks in advance.
//first code
public void deleteList()
{
Node n = head;
Node n1;
head = null;
System.out.println("Deleting list");
while(n != null)
{
n1 = n;
n = n.next;
n1 = null;
}
n1 = n;
n1 = null;
System.out.println("List deleted");
}
//second code
public void deleteList()
{
head = null;
}
It depends on your implementation. If your Node class is internal only (so you don't ever return a Node where it might be saved) and you don't hold any in statics, then there should be no path to any node from a garbage collection root and GC will get rid of them.
So it's probably right, unless your implementation is doing something unusual. (I'm also assuming you don't have a tail variable or anything else that references an internal Node, because those would also need to be set to null).
The Garbage Collector will destroy an object only when the particular object doesn't have any linked internal dependency to other nodes. In other words, whenever the objects are not referenced anymore, they are destroyed and their memory is reclaimed.
your first code is right, when you have internal dependency with other nodes i.e, tail node, for example.
your second is right, when you doesn't have any dependency with other node.

Setting Head in a Linked List

I am trying to make a Linked List I have a working insert method however I don't know how to set head to the front of the list.
public void insert(Object o) {
curr = new Link(o,curr);
if(ticker ==0){
head = curr;
tail = curr;
}
ticker++;
}
This just sets head to the end of the list when it needs to be in the front. Any help would be much appreciated. And if you need anything else to figure this out let me know.
I don't exactly know what your Link is, but I think you should create a Node class like
class Node {
Object value;
Node next;
Node pre; // optional
}
And your head and tail will be a instance of Node.
I think your problem lies in the constructor for Link. Based on your result, the new Link stores a reference to the old Link; this is reversed, and thus your list is built in reverse. Set the Link argument's next node to the Link being instantiated, something like
public Link(Object value, Link previous) {
...
previous.nextLink = this;
...
}
The head of a linked list refers to the first element that was added, not the last, as you indicated in your comment. That's just the terminology.
You need an else branch in your insert method setting tail = current, so you always have a reference to the end of the list. (head already points to the beginning of the list, and which node is the head won't change) In fact, if you do this, you won't even need the variable tail, since current will serve the same purpose.

Reversing a doubly-linked list with dummy nodes by using 'head.next' as a start point instead of 'head'

First and foremost, I have a working implementation of a reverse() method and I'm not looking for help on how to do it as it is a homework question. My problem is an error I ran into doing what I thought would save an iteration on my while loop by starting with the first real element in the list, rather than the head dummy node.
The working reverse() method code:
public void reverse() {
Node<T> current = head;
Node<T> temp = null;
tail = head;
while(current != null) {
temp = current.prev;
current.prev = current.next;
current.next = temp;
current = current.prev;
}
head = temp.prev;
}
And an example of the program with which it belongs to running into the error:
https://ideone.com/KKUtMn
The change that breaks my program:
Node<T> current = head.next;
Making that change causes a NullPointerException on any calls to addLast(x) after a call to reverse() is made. The call to reverse() reverses the list without error or issue and I can call addFirst(x) just fine, but the first call to addLast(x) will throw the exception. I find it especially odd because the call to addLast(x) uses the tail dummy node to insert the element, but the only usage of tail in reverse() is assigning it prior to the loop and shouldn't be affected by whatever current gets referenced to.
The reason I thought I'd make the change is because that first iteration on head seemed useless when it just got reassigned to temp.prev after the while loop anyway. I didn't need the traversal offered by the loop either since I could simply point directly to the first non-dummy node from the start. I'm obviously wrong as the idea doesn't work, but I can't figure out the logic that makes that so.
Any ideas?
The problem is that you still set tail = head in the beginning. Since you never reverse the prev and next of your previous head, it will not HAVE a prev, only a next. Which causes the NullPointerException when you call addLast and he tries to get the prev of the tail ;)
You could move to the end of the list
while(current.next != null){
current = current.next;
if you are at the end, you start to swap the node's next reference...
current.next = curr.prev
and so on

Java: How to create a queue based on a Node class

I'm trying to create a queue using two classes, a Node class and a Queue class for an assignment. Here's the node class:
class Node
{
protected Node next;
public Node()
{
next = null;
}
}
This class basically links the data together using a Node.next object. I've successfully been able to create a stack with push() and pop(), because the two operations happen on the same end, so the point are just manipulated between pointing to a new added node, and the previous node.
However, I'm having some difficulties understanding the logic to create a queue based on a similar structure. My queue class looks something like this:
class Queue
{
private Node footer;
private Node header;
public Queue()
{
footer = null;
header = null;
}
public void add(Node newNode)
{
//Adds onto the queue from the 'footer' end.
}
public Node remove()
{
//Removes from the queue from the 'header' end.
}
Here's what I understand: (1)The header and the footer point to the same first node. (2) Subsequent adding should change the footer to point to the added nodes, but the header stays on the first node added. (3) The header should point to the next oldest node upon removal.
Here's what I can't figure out (and where it's different than popping from a stack). How do I get the header to point to the 'next oldest node', given that I have more than 2 nodes in this queue? I know I can do this if I link header.next to the next node in the queue, but how can I access the next node so that it can point to it?
I thought about how in add(), the newNode.next should point to the next newNode (reverse direction of a Stack), but this can't work because the next newNode isn't in existence yet.. Another idea was to modify the Node class to have a Node.previous for a way to point backwards, but I would be breaking specification for this assignment.
My instructor hinted something about "header.next will point for second item as header and footer point to first node initially," and that the way to do this is pretty simple. However, I've been drawing how this works, and I'm confused how the initial pointing to the same node will allow header.next to "automatically" point to the next oldest node, especially if more and more nodes are added and the footer eventually is separated from the header by more than 2 nodes. Is there something about OOP I'm not seeing?
Any help would be great!
To expand on, and offer a subtle alternative to #Sanjeev's answer (one that I think your instructor was hinting to):
Rather than using footer to store "actual" nodes, use it as a placeholder: Declare it as a final variable, initialize it in your constructor and make sure that either a) it's next node is always your header (this would be called a circular list), or its next node is null.
Can you see how this solves your "this can't work because the next newNode isn't in existence yet" problem: Of course you can't point the last node added to the next one that will be added before adding it - instead, you point it to this "dummy" node - which is a placeholder for the next node that will be added, when and if it is.
add(Node newestNode){
identify the last node added as the one whose next property is the footer.
change the next property of that node from footer to this new newestNode
set the next property of this new newestNode to footer
}
It would be preferable to identify that last node added as the one that footer is pointing to (rather than the one pointing to footer), which would be easy if you were allowed to have previous as well as next properties on nodes, but it sounds like you're not allowed to do that. Of course, since we're using footer as a "dummy node", we could simply use footer.next the way we would footer.previous and have it point backwards instead of forwards, but I'll leave you to consider how clean that would be. There are other options here that I'll leave you to consider as well.
How do I get the header to point to the 'next oldest node'`
The "oldest" node was the first one added. The "newest" node is the last one added. How is the order of the rest of the nodes stored? The same way it was in your Stack - by traversing a chain of references stored as instance variables on your nodes. The main point I want to make is that Stacks and Queues, when implemented as linked data structures, are much more similar than you seem to be thinking, at least from a : Iterating through any linked data structure is done by following traversing these links - don't get too hung up on the fact that you're "moving" in a different direction - the same basic principles apply:
Node remove(){
identify the "oldest" node as header.next.
Store a reference to that node so you can return it.
identify the "second oldest node" as header.next.next
change header.next to header.next.next
return the reference to the old header.next you saved above.
(Note that using header/footer as placeholders, rather than storing "actual" nodes in them as #Sanjeev suggests, is not necessary, but it'll make your life easier - for instance, by helping you avoid a lot of null checking)
Here is the sudo code that will help you get started.
public void add(Node newNode)
{
if footer is null ?
then
header = newNode and footer = newNode;
else
footer.next = newNode and footer = newNode;
end if
}
public Node remove()
{
Node returnMe = header;
if header is not null?
then
header = header.next
if header is null
then
footer = null;
endif
end if
return returnMe;
}
How do I get the header to point to the 'next oldest node', given that
I have more than 2 nodes in this queue? I know I can do this if I link
header.next to the next node in the queue, but how can I access the
next node so that it can point to it?
To make header point to that node, you only need do header = header.next. The reason is that Java objectt assignment is by reference. Since header.next is type of Node, header is type of Node, it will copy the address of header.next to header, i.e., header is advanced one place.
I thought about how in add(), the newNode.next should point to the
next newNode (reverse direction of a Stack), but this can't work
because the next newNode isn't in existence yet..
I think it is no need to considering reverse direction. The reason is because for adding , it is to add element to the tail/footer of the queue. The only special case is that the queue didn't have any elements (footer == header == null), 1 element : (footer = header = element), other case: header won't change, but you need to append element to footer, and then make footer point to the new node.
When only 1 element, footer.next == header.next == null
The first thing that you need to do is make sure the first node you create is the oldest so it should be the first to be removed from the Queue based on First In First Out (FIFO) principle to archive this you might need to modify you're add method to something like this, by the way this example is based on single linked list implementation.
void add(char new_data)
{
/* 1. alloc the Node and put data*/
Node new_Node = new Node(new_data);
/* 2. Make next of new Node as head */
new_Node.next = head;
/* 3. Move the head to point to new Node */
head = new_Node;
}
then you will need a remove method which will remove the oldest node on the list first remember in Queue the order of remove is First In First Out (FIFO)
that being said this remove method should help you
void remove()
{
// Store head node
Node temp = head, prev = null;
// If head node itself holds the key to be deleted
if (temp != null )
{
head = temp.next; // Changed head
return;
}
// Search for the key to be deleted, keep track of the
// previous node as we need to change temp.next
while (temp != null)
{
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;
}
This worked for me on my linked list

removing element from LinkedList

I'm trying to remove the last node from a linkedList and return it. This is part of a Linkedlist class. The following method that I wrote doesn't delete the last node. Does anybody know why?
public int delete(){
if(front==null){
throw new NoSuchElementException();
}else{
ListNode current = front;
while(current.next!=null){
current = current.next;
}
int delete = current.data;
current = null;
return delete;
}
}
Setting current to null only changes the reference to null. It in no way affects the linked list data structure. You need to find the second to last node and set its next pointer to null:
int data = secondToLastNode.next.data;
secondToLastNode.next = null;
return data;
Of course, you'll need to handle the situation where there is only one node in the list which the above code doesn't account for.
You are only setting your local reference current to null; you're not changing your list.
Assuming this is a singly linked list, you will need to set the second-to-last ListNode's next to null (or set front to null if it's the only item).
There are three situations you need to cover:
There are no entries in your list. Usually you just exit in this case but throwing an exception like you do should be fine.
There is only one entry in your list. In this case your variable front will have a value but front.next will be null. You should set front to null in this case.
For none of the above you should set the next of the last but one entry to null. You have not managed to do this yet.
I wound up explaining this here.
Jave is a pass-by-reference language and = reassigns the reference. You're only changing local references, see sample code in above link and understand that.
Remember the 'current' before the one that has the null pointer, and set the 'next' pointer of that node to null. That way, you delete the reference to the latest node, instead of just updating a local variable.
Try this one
public int delete(){
if(front==null){
throw new NoSuchElementException();
} else if(front.next===null){
return front.data;
}else{
ListNode current = front;
while(current.next.next!=null){
current = current.next;
}
int deleted_node = current.next.data;
current.next = null;
return deleted_node;
}
}

Categories

Resources