How to delete tail in Double Link List? - java

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.

Related

Recursive code for reversing a linked list is not working properly

Here tail is a pointer to the last element of linked list.
This code only works when there are odd numbers of nodes in a linked list and shows wrong output for even number of nodes. Please help what is the problem in the code and reason why it is happening?
public static class Node
{
int data;
Node next;
}
public static class LinkedList
{
Node head;
Node tail;
int size;
// many other member functions
private void reversePRHelper(Node node , Node prev)
{
if(node == null)
{
return;
}
Node Next = node.next;
node.next = prev;
prev = node;
reversePRHelper(Next , prev);
Node temp = this.head;
this.head = this.tail;
this.tail = temp;
}
public void reversePR()
{
reversePRHelper(head,null);
}
}
The bug in your code is that these three lines:
Node temp = this.head;
this.head = this.tail;
this.tail = temp;
should only be executed once, at the end, and not for each recursive call. So if you move those three statements out of your reversePrHelper method and into your reversePR method, your code will work.
private void reversePRHelper(Node node , Node prev)
{
if(node != null)
{
return;
}
Node Next = node.next;
node.next = prev;
prev = node;
reversePRHelper(Next , prev);
}
public void reversePR()
{
reversePRHelper(head,null);
Node temp = this.head;
this.head = this.tail;
this.tail = temp;
}
For me it is unclear however why you keep the tail as an attribute, since you can't navigate anywhere from the tail, as it has no next value. It would be different if your nodes would keep a reference to the previous element as well, but then it would be a double linked list.

Doubly LL insertion at end stuck on loop

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.

Object is getting updated without that object reference?

//I have a Node.java Class
public class Node{
int data;
Node next;
public Node(int d) {
data = d;
}
}
//And another java class
class LinkedList {
Node head;
public static void main(String[] args) {
LinkedList list = new LinkedList();
//Executing this loop
for (int i = 0; i < 5; i++) {
**list.add(i);**
}
}
void add(int value){
Node newNode = new Node(value);
if(head == null )//Very first time its create the head object when i = 0
{
head = newNode;
}else if(head.next == null){//This is for when i value is 1
head.next = newNode;
}else{ //else part execute i >= 2
//Created new node with head.next which mean value 1.And head is 0
Node temp = head.next;
// Just need this object initialization for reference
Node temp1 = newNode;
//Checking head.next is null or not if its null skip this loop execution
while(temp != null)
{
temp1 = temp;
temp = temp.next;
}
// Here we set newNode.next to null
newNode.next = temp1.next;
temp1.next = newNode;
}
}
}
My Question is here , when temp1.next = newNode; line execute head object have added
one next value.
**
//For example if head = 0,head.next = 1 when temp1.next = newNode; line execute head.next.next = 2 is getting added with head. How its happening when we do not have head object reference.
You are not updating the head object.
You are updating the head.next object.
So
head.next.next
can be written like this:
Node nextFromHead = head.next; // nextFromHead is 1
Node nextFromNextFromHead = nextFromHead.next; // nextFromNextFromHead is 2
head.next.next is the same object as nextFromNextFromHead but it ( the Node that is 2 ) doesn't have any direct connection to the head node.
I think this will help better understand how references work in java.
public class LinkedList {
static Node head;
public static void main(String[] args) {
LinkedList list = new LinkedList();
for(int i = 0; i < 5; i++)
list.add(i);
Node currentNode = head; // in java we don't need object initialization for reference. Node temp1; would work just fine
System.out.println("==head node== " + currentNode);
while(currentNode.next != null) {
// here we increment
currentNode = currentNode.next;
// System.out.println("Last time we in here, next is null so print only current");
System.out.println("==next node== " + currentNode);
}
}
void add(int value){
Node newNode = new Node(value);
if(head == null )//Very first time its create the head object when i = 0
{
head = newNode;
}else if(head.next == null){//This is for when i value is 1
head.next = newNode;
}else{ //else part execute i >= 2
//Created new node with head.next which mean value 1.And head is 0
Node temp = head.next;
// Just need this object initialization for reference
Node temp1 = newNode;
//Checking head.next is null or not if its null skip this loop execution
while(temp != null)
{
temp1 = temp;
temp = temp.next;
}
// Here we set newNode.next to null
System.out.println(" ==temp1== " + temp1);// before
newNode.next = temp1.next;
temp1.next = newNode;
System.out.println(" ==temp1== " + temp1);// and after
}
System.out.println("==current node== " + head);
System.out.println();
}
}
And the Node class with an additional toString() for properly viewing the objects.
public class Node {
int data;
Node next;
public Node(int d) {
data = d;
}
#Override
public String toString() {
return "Node{" +
"data=" + data +
", next=" + next +
'}';
}
}
"You" do have the head element.
Have a look at your code: your LinkedList class has a field head; and whenever you call the add() method of your list; that field is accessible by that method.
So, adding works like this:
If the head is not set, a new one is created
If the head is set, but has no "next", then that next node is created and linked to head
If the head is set, and his "next", then you keep retrieving the "next" next ... until you find one the last one; which doesn't have a next (yet) ...
That is all there is to understand. Or lets try some non IT-example.
Assume you some hook and short ropes; and you want to build a "list of ropes".
No list yet. You take the first rope and attach it to the hook.
The first rope, your head, is there. You add another rope, by connecting it to the end of the first one (probably making a knot)
Adding another rope ... you start at the hook, and you keep following the ropes/knots ... until you have a loose end.
Hope that helps.

Inserting Node in a Sorted linked list

The following code ensures that elements are inserted in a linked list in a sorted manner.
After understanding the logic behind this i decided to test it on my own. However when i wrote my version of the code it as follows.
public class SortedList {
private Node first;
public SortedList() {
first = null;
}
public boolean isEmpty() {
return first == null;
}
public void insert(int j) {
Node newNode = new Node(j);
Node previous = null;
Node current = first;
while (current != null && j > current.iData) {
previous = current;
current = current.next;
}
if (previous == null)
first = newNode;
else
newNode.next = current;
previous.next = newNode;
}
public Node remove() {
Node temp = first;
first = first.next;
return temp;
}
public void displayList() {
System.out.println("First to -----> Last");
Node current = first;
while (current != null) {
current.display();
current = current.next;
}
}
}
NODE CLASS
public class Node {
public int iData;
public Node next;
public Node(int id) {
iData = id;
}
public void display() {
System.out.println(iData + " ");
}
}
TEST CLASS
public class SortedListApp {
public static void main(String[] args) {
SortedList list = new SortedList();
list.insert(20);
list.insert(40);
list.displayList();
list.insert(10);
list.insert(30);
list.insert(50);
list.displayList();
list.remove();
list.displayList();
}
}
The only difference between the two is that in my version when the while loop terminates. I first set the next value of the newNode to the current and then i set the next value of previous to the new Node. In the original code posted they have it reversed. For some reason this throws Null Pointer Exception. I am wondering why?
From what i understand, once the new node finds its place for insertion. We have reference to the previous node and the current node and we are trying to insert the new node in the middle of the previous and the current. Therefore what i do is set the next of the new Node to the current and then i set the next of previous node to the new node.
Please tell me where i am wrong.
Trace through this code when previous is null:
if (previous == null)
first = newNode;
else
newNode.next = current;
previous.next = newNode;
Notice that you never actually changed previous in the if statement, so this will try to write the next field of null, causing the crash.
If previous is null, then you need to prepend the node to the list, and in that case all you need to do is set first to newNode and make newNode's next pointer point to the old list. In the case where previous isn't null, then you need to do two rewirings: you need to make previous.next point to the new node and for the new node's next pointer to point to the current node. You can fix this by writing
if (previous == null) {
newNode.next = current;
first = newNode;
}
else {
newNode.next = current;
previous.next = newNode;
}
Equivalently:
newNode.next = current;
if (previous == null)
first = newNode;
else
previous.next = newNode;
Hope this helps!

Shift elements in a linked list in java

I have to shift all of the tokens left by one position in a Linked List.
Here's my code for the method:
private LLNode<E> head; // the first node in the list
private LLNode<E> tail; // the last node in the list
public void shiftLeft()
{
LLNode<E> temp = new LLNode<E>();
temp = head;
head = head.next;
tail.next = temp;
}
/*from main method
TopSpinLinkedList<Integer> ll = new TopSpinLinkedList<Integer>(numTokens, spinSize);
//fills LinkedList with tokens
for(int i = 1; i <= numTokens; i++) {
ll.add(i);
}
*/
A nullpointer error appears during runtime when I call the method. Any help would be appreciated. Thanks.
If it is circular linked list and your add method works properly.
public void shiftLeft(){
head = head.next; tail = tail.next;
}
You have to think about some points:
1) If your link list does not contain any element then what?
2) For all tokens to be shifted you have to use while-loop.
I assume that head and tail are properly updated on insert and remove
public void shiftLeft()
{
if(head == null || head.next == null){
return;
}
LLNode<E> temp = new LLNode<E>();
temp = head;
head = head.next;
temp.next = null;
tail.next = temp;
tail = temp;
}
UPDATE:
From the comment I see that the OP mentions about a circular list. This is not mentioned in the OP or apparent from the code. I will leave the answer as is.

Categories

Resources