I can't seem to figure out why inserting a node at the end of a doubly linked list is getting stuck in a loop. Either its stuck in a loop or null pointer. Also I'd like to know if public Node is better or public void when dealing with linked lists or any data structures.
public Node insertEnd(int data) {
Node newNode = new Node(data);
newNode.next = null;
if (head == null) {
head = newNode;
return newNode;
}
Node last = head;
while(last!=null) {
last = last.next;
last.next = newNode;
}
newNode.previous = last;
return newNode;
}
Well, its because of this part of the logic
Node last = head;
while(last!=null) {
last = last.next;
last.next = newNode; //// This shouldn't happen.
}
Once the linked list is already created, you're trying to go to the last element. However, during that traversal you've also changed the next pointer to which the node was pointing to.
Try to change your logic to:
public Node insertEnd(int data) {
Node newNode = new Node(data);
newNode.next = null;
if (head == null) {
head = newNode;
return newNode;
}
Node last = head;
while(last.next != null) {
last = last.next;
}
last.next = newNode;
newNode.previous = last;
return newNode;
}
In your while loop:
while(last!=null) {
last = last.next;
last.next = newNode;
}
The second line sets last.next to newNode so on the next iteration, last will be set to newNode, who's next field is null. You only want to set last.next to newNode once last.next == null (When you have reached the end of the list):
while(last.next != null) {
last = last.next;
}
last.next = newNode;
As for the second part of the question, it depends on the way a client/caller of this API would expect the output to be.
Are you writing this API to be used in another program you're writing? In that case, think about if it will be useful for you to get the newly created Node as a return value of this API, or if it is acceptable to leave it as void.
For reference, the Java implementation of the API has void as the return type. (https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#addLast(E))
To answer 1st part , you need to make following changes in your code -
Node last = head;
while(last.next!=null) { // be careful- it should be last.next!=null instead of last!=null , as it will give null pointer exception.
last = last.next;
}
last.next = newNode;
newNode.previous = last;
return newNode;
as the statement "last.next = newNode;" in while loop was setting last to newNode in the first iteration itself.
for 2nd part of your question, it depends on the requirement of calling function.
Related
My teacher guides us in this activity on how to delete the tail of the double link list. He created an step by step process or algorithm for us to follow. I followed it, but it doesn't work. Or maybe I am following it wrong. Here is the algorithm
Check if the list is empty
If not Empty
Check if there is only one node in the list
If only one node, set the head and tail reference to null.
if more than one node
create a temptail to point to next tail (tail.prev)
set the prev of the tail and next of temptail to null
assign the temptail value to the tail
Here is my code
public void delTail(){
DoubleNode temp;
if(isEmpty()){
return;
}
else if(!isEmpty()){
if(head == tail){
head = tail = null;
}
else{
temp = tail.next;
tail.prev = null;
temp.next = null;
temp = tail;
}
}
}
This is the error that i saw error in my terminal
I think that I am following it right or maybe not? Thank you so much for your help :)
This is my constructor*
public class DoubleNode{
public DoubleNode prev;
public int data;
public DoubleNode next;
public DoubleNode(int d){
this(null, d, null);
}
public DoubleNode(DoubleNode p, int d, DoubleNode n){
prev = p;
data = d;
next = n;
}
}
this is mt entire operator code*
public class operator{
DoubleNode head;
DoubleNode tail;
DoubleNode laman;
String output = "";
public operator(){
head = tail = null;
}
public boolean isEmpty(){
return head == null;
}
public void addHead(int i){
if(isEmpty()){
head = tail =new DoubleNode(i);
}
else{
head = new DoubleNode(null, i, head);
head.prev = head;
}
}
public void addTail(int i){
DoubleNode last = new DoubleNode(i);
if(isEmpty()){
head = tail = new DoubleNode(i);
}
else{
tail.next = last;
tail = last;
}
}
public void delHead(){
DoubleNode temp = head.next;
if(head==tail){ //this if condition is testing if the head and tail is one only,
head = tail =null; //if there is only one this will set the tail and head to null
}
else{
head = head.next;
head = temp;
}
}
public void delTail(){
DoubleNode temp;
if(isEmpty()) {
return;
}
else {
if(head != tail) {
tail = tail.prev;
temp = tail;
}
else {
head = tail = null;
}
}
}
public void display(){
DoubleNode tmp = head;
output = "<html>";
for(tmp = head; tmp != null; tmp = tmp.next){
output = output + "<br>" + tmp.data + "<b>" + "<br>";
}
output = output + "</html>";
}
}
This is my entire code so far, i have a main class with a jframe but i think its fine because i also use it for single link list. But I do have a problem here at double link list regarding on deleting the last node
Your problem is that you're just assigning to temp but don't actually use it. Additionally you're not setting the link back to the previous element correctly.
Assuming tail.next points to head again you might do the following:
tail.prev.next = tail.next; //you might need to check for `tail.prev` being null
tail.next.prev = tail.prev; //you might need to check for `tail.next` being null
//delete tail
To illustrate:
A -next-> Tail -next-> Head
^---prev--+ ^---prev--+
Step 1:
+----next--------------V
A Tail -next-> Head
^---prev--+ ^---prev--+
Step 2:
+----next--------------V
A Tail -next-> Head
^---prev--+ |
^--------------prev----+
Actually if tail.next == head removing the tail is no different than removing any other node.
You have two errors in your else block:
You never change the tail reference. The last statement should really be an assignment to tail.
You seem to assume that the tail has a non-null next reference, but that is a contradiction. The tail is supposed to be the last node, so its next reference will always be null (unless you are supposed to create a circular list). By consequence, temp will be null, and the statement temp.next = tail will trigger the Null Pointer Exception.
The more interesting property of tail is its prev property, which refers to the node that will become the tail after the current tail node has been removed. This tail.prev is explicitly mentioned in your assignment.
So:
else {
temp = tail.prev; // <--- should point to the new tail
tail.prev = null;
temp.next = tail;
tail = temp; // <--- reverse the assignment
}
Several other issues...
In addHead you do not set the prev property correctly. You make it a self-reference. Realise that head is already referencing the new node. Change:
head.prev = head;
to:
head.next.prev = head;
In addTail the assignment to prev is missing. Change:
tail.next = last;
tail = last;
to:
tail.next = last;
last.prev = tail; // needed!
tail = last;
In delHead you must make sure the new head's prev is null. So change:
head = temp;
to:
head = head.next;
head.prev = null;
NB: you don't need DoubleNode temp = head.next; in that method.
Here is the piece of code in java for inserting node at the end of the circular linked list, but its not working using this function but when I saw in the internet and used that then it worked. Can anyone suggest me that what is wrong with this piece of code?
//PUSH NODE AT END IN CIRCULAR LL
public void pushEnd(int new_data){
Node new_node = new Node(new_data);
if(head == null){
head = new_node;
new_node.next = head;
}
else{
Node temp = head;
while(temp.next!=null){
temp = temp.next;
}
temp.next = new_node;
new_node.next = head;
}
}
Does any node in a circular linked list have its next field as null ? If it is, then its not a circular linked list. In your code you are looping until you find a null for the next. In fact after the first inserted node , for the next insert the loop while ( temp.next != null ) never ends.
You need to get to the node whose next is head, that's your last node for the moment. You need to push your new node after that.
So your code should be:
public void pushEnd(int new_data){
Node new_node = new Node(new_data);
if(head == null){
head = new_node;
new_node.next = head;
}
else{
Node temp = head;
while(temp.next!=head){
temp = temp.next;
}
temp.next = new_node //assign the temp's next to new_node.
new_node.next = head; //then assign new_node's next to head
}
}
It's a circular list. temp.next will never be null, and so your while loop will never end. You need to change your logic a bit and check when temp.next == head.
I've traced through my code to reverse a linked-list using recursion, and I cannot find anything wrong with it, but I know it does not work. Can anyone please explain why?
Node reverseLL (Node head) {
if(curr.next == null) {
head = curr;
return head;
}
Node curr = head.next;
prev = head;
head.next = prev;
head = next;
reverseLL(head.next);
}
Below is a working version of your code, added with some helping structures:
class LList {
Node head;
void reverse() {
head = rev(head, head.next);
}
private Node rev(Node node, Node next) {
if(next == null) return node; //return the node as head, if it hasn't got a next pointer.
if(node == this.head) node.next = null; //set the pointer of current head to null.
Node temp = next.next;
next.next = node; //reverse the pointer of node and next.
return rev(next, temp); //reverse pointer of next node and its next.
}
}
class Node {
int val;
Node next;
public Node(int val, Node next) {
this.val = val;
this.next = next;
}
}
You need to call reverseLL(head.next) before the switching, to traverse down the list and start from the last node upwards. This requires some more changes though.
There are two possible implementation.
First one with a pointer to the head (a class attribute) within your class
class Solution:
head: Optional[ListNode]
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
if node == None:
return node
if node.next == None:
self.head = node
return
self.reverseList(node.next)
q = node.next
q.next = node
node.next = None
return self.head
Second solution, does not rely on a class attribute to conserve the head once you find it. It returns the pointer to the head through the recursive calls stack
def reverseList(head):
# Empty list is always None
if not head:
return None
# List of length 1 is already reversed
if not head.next:
return head
next = head.next
head.next = None
rest = reverseList(next)
next.next = head
return rest
I am trying to delete nodes with a given key and also want to display the updated Tail and Head node values. I am able to delete first node (Head) and cannot delete Tail node Please check my code below
public void delete(int key){
Node current = head;
while(current.next.data != key){
current = current.next;
}
if(current.next.data == key ){ //deleting current node
current.next = current.next.next;
if(current.next == head)
tail = current;
else if(current == head)
head = current.next;
}
}
My Main method:
public class Caller {
public static void main(String args[]){
Linklist theList = new Linklist();
theList.insertFirst(22);
theList.insertFirst(44);
theList.insertFirst(55);
theList.insertFirst(66);
theList.delete(22);
System.out.println("deleting 22");
theList.display();
theList.delete(66);
System.out.println("Deleting 66");
theList.insertLast(99);
theList.insertLast(11);
theList.display();
}
}
my insertLast method:
public void insertLast(int data){
Node newNode = new Node(data);
Node current = head;
while(current.next != head){
current = current.next;
}
current.next = newNode;
newNode.next = head;
tail = newNode;
}
and my output is :
deleting 22
Displaying list first ----> last
{ 66 }
{ 55 }
{ 44 }
Head : 66 Tail: 44
Deleting 66
Nothing happens after this code
This is one of the problems which are best solved by running through the algorithm step-by-step with pen and paper. I think the problem is not in removing the tail node, which your own log output shows as working, but in deleting the head node ('66' in this case). Yes, '66' was inserted last, but it was inserted upfront of anything else already in the list, thus making it the head node.
The problem is that you change the cyclic list's structure before you update the head/tail pointers. In the case of removing the head node, when the code gets to the current.next = current.next.next; line, current points to the tail node, current.next is the head node, and current.next.next is the head+1 node. By executing the assignment, current.next is made to point to the head+1 node, meaning that neither if(current.next == head) nor else if (current == head) will trigger. The head node is now outside of the cyclic list, but the head pointer still points to that node; and worse, head.next still points into the cyclic list.
Two more issues:
Major: the delete() method does not handle the removal of the last element of the list
Minor: the if(current.next.data == key ) is unnecessary because it is literally the stopping condition for the preceding while-loop.
I kept track of previous and current node and it worked!
public void delete(int key){
Node current = head;
Node prev = current;
while(current.data != key){
prev = current;
current = current.next;
}
if(current.data == key ){ //deleting current node
if(current == head){
prev = tail;
head = current.next;
}else if(current == tail){
tail = prev;
head = current.next;
}
prev.next = current.next;
}
}
I am working on my Computer Science studies and I am having some difficulty with adding a Node to the end of a doubly linked-list data structure. I understand that the new node points to the tail and the tail points to it, thus I have this:
public boolean add(E element)
{
// TODO: Implement this method
LLNode<E> newNode = new LLNode<E> (element);
if (element == null) {
throw new NullPointerException("Element can not store a null reference!");
} else {
newNode.next = tail;
newNode.prev = tail.prev;
tail.prev = newNode;
head.next = newNode;
}
size++;
return true;
}
The issue I'm having is trying to connect the head node (via head.next to the correct node).
In my default constructor, I have the head.next node pointing to tail.prev. However in the add method, I could not figure out where head.next would point since each time you add a new node, head has to point to the first node in the LinkedList Data Structure. Here is the default constructor:
public MyLinkedList() {
// TODO: Implement this method
size = 0;
/*create two empty nodes at the head and the tail of the linked list*/
head = new LLNode<E> (null);
tail = new LLNode<E> (null);
head.next = tail;
tail.prev = head;
head.prev = null; //Head is a sentinel node with no node prior to it
tail.next = null; //tail is a sentinel node with no node after it
}
Please point me (no pun intended) to the right direction. Thanks!
Draw on paper what you have to do.
E.g. if you list current has two elements (A and B), you chain will be:
HEAD <-> A <-> B <-> TAIL
To add a new element (C), your end result should be:
HEAD <-> A <-> B <-> C <-> TAIL
which means the following updates:
C.prev = B or more precisely: C.prev = TAIL.prev
B.next = C or more precisely: TAIL.prev.next = C
C.next = TAIL
TAIL.prev = C
As you can see, HEAD is not involved in this, so your line head.next = newNode is wrong.
This should work.
public boolean add(E element)
{
LLNode<E> newNode = new LLNode<E> (element);
if (element == null) {
throw new NullPointerException("Element can not store a null reference!");
} else {
newNode.next = tail; // set new.next to tail
newNode.prev = tail.prev; // set new.prev to prior last
tail.prev.next = newNode; // set prior last.next to new last
tail.prev = newNode; // set tail.prev to new last
size++;
}
return true;
}
I'm not sure if the check for null element is needed in an add function, although a null check may be needed elsewhere.
I think you need to rethink how you handle the linked list...
You start with a linked list Like this:
head.next = tail
head.prev = null
tail.next = null
tail.prev = head
and when you add something to the end of the list, lets call it mid, you want your list to look like this:
head.next = mid (set by using tail.prev.next = mid)
head.prev = null
mid.next = tail (the new node is the end of the list)
mid.prev = head (previous tail.prev)
tail.next = null
tail.prev = mid (setting the new node to be the new end of the list)
So your mistake is that when you are adding a node, you shouldn't be using the head node explicitly, like you are doing. All operations should be done in terms of the tail of the list. I've it leave it up to you to turn this into code.