Inserting a node into a linked list in constant-time? - java

I'm working on an assignment that is telling me to assume that I have a singly linked list with a header and tail nodes. It wants me to insert an item y before position p. Can anybody please look over my code and tell me if I'm on the right track? If not, can you provide me with any tips or pointers (no pun intended)?
tmp = new Node();
tmp.element = p.element;
tmp.next = p.next;
p.element = y;
p.next = tmp;
I think I may be wrong because I do not utilize the header and tail nodes at all even though they are specifically mentioned in the description of the problem. I was thinking of writing a while loop to traverse the list until it found p and tackle the problem that way but that wouldn't be constant-time, would it?

Just write it down if you get stuck with an algorithm:
// First we have a pointer to a node containing element (elm)
// with possible a next element.
// Graphically drawn as:
// p -> [elm] -> ???
tmp = new Node();
// A new node is created. Variable tmp points to the new node which
// currently has no value.
// p -> [elm] -> ???
// tmp -> [?]
tmp.element = p.element;
// The new node now has the same element as the original.
// p -> [elm] -> ???
// tmp -> [elm]
tmp.next = p.next;
// The new node now has the same next node as the original.
// p -> [elm] -> ???
// tmp -> [elm] -> ???
p.element = y;
// The original node now contains the element y.
// p -> [y] -> ???
// tmp -> [elm] -> ???
p.next = tmp;
// The new node is now the next node from the following.
// p -> [y] -> [elm] -> ???
// tmp -> [elm] -> ???
You have the required effect, but it can be more efficient and I bet you can now find out yourself.
It is more clear to write something like:
tmp = new Node();
tmp.element = y;
tmp.next = p;
p = tmp;
Which of course does not work if p is not mutable. But your algorithm fails if p == NULL.
But what I meant to say, is, if you have problems with an algorithm, just write the effects out. Especially with trees and linked lists, you need to be sure all pointers are pointing to the righ direction, else you get a big mess.

Hint: insertion into a linked list is only constant when position n = 0, or the head of the list. Otherwise, the worst-case complexity is O(n). That's not to say that you cannot create a reasonably efficient algorithm, but it will always have at least linear complexity.

The reason why the header and tail node is given in the question is to the update the header and tail reference if the the replacement node that your creating happens to become the header or tail. In other is words, the given previous node is either a header or tail.

What you are not doing is linking the element that was before p prior to insertion of y to y. So while y is inserted before p, no one is pointing to y now (at-least not in the code snipped you showed).
You can only insert in constant time if you know the positions of the elements between which you have to insert y. If you have to search for that position, then you can never have a constant time insertion in a single link list.

How about using code that is already there? LinkedHashMap, LinkedList, LinkedHashSet. You can also check out the code and learn from it.

create a node ptr
ptr->info = item //item is the element to be inserted...
ptr->next = NULL
if (start == NULL) //insertion at the end...
start = ptr
else
temp = ptr
while (temp->next != NULL)
temp = temp->next
end while
end if
if (start == NULL) //insertion at the beginning...
start = ptr
else
temp = start
ptr->info = item
ptr->next = start
start = ptr
end if
temp = start //insertion at specified location...
for (i = 1; i < pos-1; i++)
if (start == NULL)
start = ptr
else
t = temp
temp = temp->next
end if
end for
t->next = ptr->next
t->next = ptr

In a singly LinkedList only adding a Node to the beginning of the list or creating a List with only one Node would take O(1). OR as they have provided the TailNode also Inserting the Node at End of list would take O(1).
every other inserting operation will take O(n).

The whole explanation and the 2 codes are in Java... but its easy to translate it to any other language of your choice.
I do want to help you however I am a beginner myself...
Still I have used the logic, sharing it from the queues implementation...
I have pasted two codes one is in O(N) the other contains a method called append which is in O(1)
Now, the explanation
declare the tail node with head node in the class
now in the method append class in the 2nd code below just look at the tail pointer
CASE 1: when LL empty
usually people check if (head == null) if true then they point the head to the
new Node and return
whereas what I have done is I checked if (tail == null) and if it was true
then tail = head = newnode meaning that the tail and head both now point to
the new Node to be added.
CASE 2: when LL is not empty
wait, haha, hear me out first, I know you might be thinking that what if the
LL has just 1 node currently, then what? well... for that...
this case 2 handles it automatically, in case 1 it sets the head and tail
equal to the newnode right, so it now just changes and modifies the tail node
keeping the head node intact.
this way, the head keeps pointing to the first node and the tail keeps updating and pointing to the newnodes created with each append function call.
Hope this explanation helps...
PS. check from line 24 for O(N) and 102 for O(1) and every time a newnode is added to the LL by the append method call, the tail will point to the new node to be added.
import java.io.*;
import java.util.*;
public class Solution {
// class Solution is what should be called as the LINKEDLIST class but its ok
Node head; // declaring a head for the LL
class Node { // Node class
int data; // the .data variable
Node ref; // .ref aka .next
Node(int data) { // constructor for initializing the values
this.data = data;
this.ref = null;
}
}
public void append(int data) { // i call 'to join at the end' as append
// O(N)
Node newnode = new Node(data); // new node creation
if (head == null) { // checking is head is null aka None in Py
head = newnode;
return;
}
Node curr = head; // assigning head to a curr node ready for traversal
while (curr.ref != null) { // traversal begins
curr = curr.ref;
} // traversal ends
curr.ref = newnode; // this is the last node where the join happens
}
public void p() { // i name printing function as p()
if (head == null) { // if head is null then print empty
System.out.println("Empty");
return;
}
Node curr = head; // same thing - traversal begins here
while (curr != null) {
System.out.println(curr.data);
curr = curr.ref;
} // by now all data values have been printed out already
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in); // scanner class for input
Solution l = new Solution(); // object creating for LL as Solution class name
int numberOfNodes = sc.nextInt(); // input for number of NODEs in LL
for (int i = 0; i < numberOfNodes; i++) { // loop for .data values
int data = sc.nextInt();
l.append(data); // function append call for each (i)
}
l.p(); // finally print func call to display output LL
}
}
class PractGG {
Node head;
Node tail;
class Node {
int data;
Node ref;
Node(int data) {
this.data = data;
this.ref = null;
}
}
public void push(int data) {
Node newnode = new Node(data);
if (head == null) {
tail = head = newnode;
return;
}
newnode.ref = head;
head = newnode;
}
public void append(int data) {
// O(1)
Node newnode = new Node(data);
if (tail == null) {
tail = head = newnode;
return;
}
tail.ref = newnode;
tail = newnode;
}
public void p() {
if (head == null) {
System.out.println("Empty");
}
Node curr = head;
while (curr!=null) {
System.out.print(curr.data + "==>");
curr = curr.ref;
}
System.out.println();
}
public static void main(String[] args) {
PractGG l = new PractGG();
l.append(1);
l.append(2);
l.append(3);
l.p();
}
}

Related

Why is new Node is not added?

public class LinkedList {
static Node head;
static class Node{
int data;
Node next;
Node(int dat){
data = dat;
next = null;
}
}
public void add(int data){
Node node = new Node(data);
Node n = head;
while (n!= null){
n = n.next;
}
n = node;
}
public void print(){
Node n = head;
while(n!=null){
System.out.println(n.data);
n = n.next;
}
}
}
I realize that in the add() method I am assigning 'node' to an item that has the value null, however, the doubt is even is n.next becomes null its still a node right because 'next' is defined as a Node, so it should work right.
To add the new node at the end of the linked list, you need to take following steps:
Create the new node
Check if linked list is empty. If it is, point the head to the new node and return from the function
If linked list is not empty, traverse the linked list until the last node is reached
Point the next of the last node to the new node created in step 1.
Problem
There are couple of problems in your code:
You are not handling the special case of adding the new node in the empty linked list
while loop in the add() method doesn't stops when the last node is reached. It only stops when n itself becomes null which means you cannot add the new node in the linked list
Solution
You need to change the condition in the while loop from
n != null
to
n.next != null
to make sure that you are at the last node in the linked list after the loop ends and then to add the new node in the linked list, you need to point the next of the last node to the new node
n.next = node;
Your add() method should be written as:
public void add(int data) {
Node node = new Node(data);
if (head == null) {
head = node;
return;
}
Node n = head;
while (n.next != null){
n = n.next;
}
n.next = node;
}

Can an object like node update itself without any need of giving it an updated value?

(In the insert method): In the else statement, I don't understand how "front.next" is getting updated with the line: "prev.next = newNode". Theoretically, I understand it, but practically, although "prev" gets its value from "curr", which got its value from "front" itself, there is no way that front is getting updated because "prev". How are they talking to each other?
(Insert method)I have tried debugging and when it reaches the else statement that executes => prev.next = newNode; front.next gets updated as well which I just don't understand since front is nowhere being initialised again. Front is an object of itself.
public class SinglyLinkedList<T>
{
// inner class being created:
protected class Node<T extends Comparable<T>>
{
T val;
Node<T> next;
Node(T val)
{
this.val = val;
this.next = null;
}
Node(T val, Node n)
{
this.val = val;
this.next = n;
}
}
private Node front, tail;
public SinglyLinkedList()
{
this.front = this.tail = null;
}
// print method:
public void print()
{
// print the contents of the list
Node curr = front;
while (curr != null)
{
System.out.println(curr.val + " ");
curr = curr.next;
}
}
// insert method:
public void insert(T val)
{
Node newNode = new Node((Comparable) val);
// make a new node
if (front == null)
{
// empty list
front = tail = newNode;
}
else
{
// list is not empty
Node curr = front, prev = null;
// look for insert point.
while (curr != null && curr.val.compareTo(val) < 0)
{
prev = curr;
curr = curr.next;
}
// insert node before curr
newNode.next = curr;
if (curr == front)
{
// update front
front = newNode;
}
else
{
// update node before
prev.next = newNode;
}
if (tail.next != null)
{
// move tail to last node
tail = tail.next;
}
}
}
}
I expected curr to keep continuing to fill in the chain of nodes using curr.next and using "prev" as a temporary node used in the process of adding a node in between two nodes.
I also didn't expect print method to work since it begins with front node. Theoretically, it does make sense to start with front node, but looking at my code how "front" is not equalling to any value, but rather "curr" equalling "front", makes me feel that "front" shouldn't be having the access to the rest chain of nodes.
I expected "front.next" to be null, but it isn't.
Well, according to your code, the front works as the first node of the linked list, it actually equals to a certain value (a real node) because your code set it to be so a
if (front == null)
{
// empty list
front = tail = newNode;
}
and
if (curr == front)
{
// update front
front = newNode;
}
See! You indeed pointed it to a certain node with a given value.
For the update question. I think possibly you are always inserting a new node right next to the front node. Under that circumstance, the prev points to the same node as the front do. So if you update prev, you are updating front, too!

Adding to the end of a Doubly-Linked List Data Structure in Java

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.

Implementing Circular Linked List in java

I'm having a bit of an issue with implementing my circularly linked list. I'm working on a problem that requires you to implement any ADT yourself. I seem to be okay with adding nodes to the list, however I'm in unfamiliar territory when it comes to removing. I included the first two remove methods to give you an idea of where my head is at, how would I go about removing the last node in the list?
public class LinkedList {
private Node head;
private Node tail;
private int size = 0;
LinkedList() {
head = null;
current = null;
previous = null;
tail = null;
size = 0;
}
//checks if list is empty
public boolean isEmpty() {
return head == null;
}
//add new node to front of circularly linked list
public void addToFront(E x) {
if (head == null) {
head = new Node(x);
} else {
Node n = new Node(x);
x.next() = head;
head = x;
}
}
public void addtoMiddle(E x) {
x.next = current.next();
current.next = x;
size = size + 1;
}
public void addToEnd(E x) {
x.next = null;
tail.next() = x;
tail = x;
size = size + 1;
}
public void removeFirst(E x) {
if (head = null) {
System.out.println("Error! List is empty!");
} else {
head = current.next();
size = size + 1;
}
}
public void removeMiddle(E x) {
previous.next() = current.next();
current.next() = null;
size = size + 1;
}
In a circular linked list the last node's next points to the head, so you loop through your nodes until node.next.equals( head ). Note that next must never be null and if you have only one node then you have head.next = head.
In a circular doubly linked list you also have a previous node, i.e. you can iterate backwards. In that case your last node is just head.previous.
A small ascii picture:
head -next---> node -next---> node -next---> last
| ^ <---prev- <---prev- <---prev- | ^
| | | |
| |_____________________________________next_| |
|_prev_________________________________________|
I know this is not directly an answer to your question but I feel like Thomas has given the needed explanation here.
Since you have a lot of syntax or incompleteness errors in the example
I would recommend to comment out all functions so it has no more errors. Then comment them in again one by one correcting every error.
Some advices:
You use class members which are not defined e.g. current, previous.
Decide if next should be a member or function.
You need to define a class for Node (containing its members and functions), like you did for LinkedList.

Delete a last node of linked list given pointer to that node

I'm trying to delete the last node of the linkedlist, given pointer only to that node.
I wrote the below implementation, but isn't working.
I already visited majority of SO questions regarding this subject, but none of them shows how to delete last node of linked list, if there's only one pointer to that node ?
Am I missing anything here ?
class Node {
Node next;
int value;
Node(int val) {
this.value = val;
this.next = null;
}
#Override
public String toString() {
Node cur = this;
String str = "";
while(cur != null) {
str += cur.value+"->";
cur = cur.next;
}
return str;
}
}
class DeleteNodeLL {
public static void deleteNode(Node current) {
Node temp;
if(current.next == null) {
current = null;
return;
} else {
current.value = current.next.value;
temp = current.next;
temp = null;
current.next = current.next.next;
}
}
public static void main(String [] args) {
Node n1 = new Node(25);
Node n2 = new Node(1);
Node n3 = new Node(36);
Node n4 = new Node(9);
Node n5 = new Node(14);
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5;
n5.next = null;
System.out.println("Original linkedlist :");
System.out.println(n1);
System.out.println();
System.out.println("After deleting a node :");
deleteNode(n5);
System.out.println(n1);
}
}
Output :-
Original linkedlist :
25->1->36->9->14->
After deleting a node :
25->1->36->9->14->
With the singly linked list it is not possible.
This is the interview questions which is typically asked in Big Shot companies which emphasizes on Data Structures.
The question is formulated as "Delete the node in single linked list given pointer to only that node"
Expected Solution:
public void deleteNode(Node n)
{
if(n==null || n.next==null)
{
System.out.println("Delete not possible");
return;
}
n.data = n.next.data;
Node tmp = n.next;
n.next = n.next.next;
tmp.next = null;
System.out.println("Node Deleted");
}
The idea is to copy the data from the next node to the current node and delete the next node. The solution does not work if the node is the last node (This is what candidate has to debate and point out in interview)
Hope it helps you! (Solution to your problem is a trick question, and it does not exists)
current = null; doesn't do what you expect - it only sets local variable (method argument) to null.
What you want is impossible with your current implementation of the Node class.
You need either a reference to the previous node inside the Node class (i.e. a doubly-linked list) or you have to provide a reference to some previous node to the deleteNode method.
I would say
You can delete the last node from the Linked List if reference of
it's previous node is given.
However it's based on how you implement the list.
For your implementation, you can't do that
The only solution to this question is to iterate over the complete list keeping the prev node pointer everytime, compare the current node with the present node. When the comparison passes, delete the last node, and point the prev node to null. Something like the code below(note: I did not compile it)
deleteNode(Node *node){
if(node){
currentNode = Head, prevNode = NULL;
while(currentNode != node){
prevNode = currentNode;
currentNode = currentNode -> next;
}
delete currentNode;
prevNode -> next = NULL;
}
}
#asifsid88 copied and pasted the solutions from "cracking the coding", you should refer to that book to find more interesting and challenging questions.

Categories

Resources