Creating a Singly Linked List from Scratch in DSA Java - Complexity Walkthrough
When we create a singly linked list from scratch, we add nodes one by one. Understanding how long this takes helps us know how the process grows as the list gets bigger.
We want to answer: How does the time to build the list change as we add more nodes?
Analyze the time complexity of the following code snippet.
class Node {
int data;
Node next;
Node(int data) { this.data = data; this.next = null; }
}
class SinglyLinkedList {
Node head;
void add(int data) {
Node newNode = new Node(data);
if (head == null) head = newNode;
else {
Node current = head;
while (current.next != null) current = current.next;
current.next = newNode;
}
}
}
This code creates a singly linked list and adds new nodes at the end one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that moves through the list to find the last node.
- How many times: For each add, it runs once for each node already in the list, so it grows as the list grows.
Each time we add a node, we walk through the existing list to find the end. So adding the first node is fast, but adding the 10th node means walking through 9 nodes first.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 0 + 1 + ... + 9 = 45 steps |
| 100 | 0 + 1 + ... + 99 = 4950 steps |
| 1000 | 0 + 1 + ... + 999 = 499,500 steps |
Pattern observation: The total steps grow roughly like the square of the number of nodes added.
Time Complexity: O(n2)
This means adding n nodes one by one at the end takes time that grows roughly like n times n, because each add walks through the list so far.
[X] Wrong: "Adding each node takes the same constant time, so total time is O(n)."
[OK] Correct: Each add after the first must walk through the existing list, so the time grows with the list size, not constant.
Understanding this helps you explain why adding at the end of a singly linked list without extra pointers is slower as the list grows. It shows you can spot where time is spent and how to improve it.
"What if we kept a pointer to the last node and updated it on each add? How would the time complexity change?"
Practice
Singly Linked List in data structures?Solution
Step 1: Understand the structure of a singly linked list
A singly linked list stores elements in nodes where each node points to the next node, forming a chain.Step 2: Compare with other data structures
Unlike arrays or trees, singly linked lists do not store keys or have parent-child relationships; they only link sequentially.Final Answer:
To store elements in a sequence where each element points to the next -> Option AQuick Check:
Singly Linked List = sequence with next pointers [OK]
- Confusing linked list with arrays or hash maps
- Thinking linked list stores key-value pairs
- Assuming linked list nodes have multiple pointers
Solution
Step 1: Identify the node structure for singly linked list
A singly linked list node contains data and a reference to the next node only.Step 2: Check each option
class Node { int data; Node next; } has data and next pointer; class Node { int data; Node prev; } has prev (used in doubly linked list); class Node { int data; Node left; Node right; } has left and right (used in trees); class Node { int data; int next; } incorrectly uses int for next pointer.Final Answer:
class Node { int data; Node next; } -> Option BQuick Check:
Node = data + next pointer [OK]
- Using 'prev' pointer instead of 'next'
- Using primitive type for next pointer
- Confusing tree node with linked list node
class Node {
int data;
Node next;
Node(int d) { data = d; next = null; }
}
public class LinkedList {
Node head;
public void add(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
} else {
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
}
public void printList() {
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " -> ");
temp = temp.next;
}
System.out.print("null");
}
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add(10);
list.add(20);
list.add(30);
list.printList();
}
}Solution
Step 1: Understand the add method behavior
The add method appends new nodes at the end of the list, preserving insertion order.Step 2: Trace the printList method
It prints nodes from head to last, showing 10, then 20, then 30, followed by null.Final Answer:
10 -> 20 -> 30 -> null -> Option DQuick Check:
Adding nodes appends at end, print shows 10->20->30->null [OK]
- Assuming add inserts at head instead of tail
- Printing nodes in reverse order
- Missing the final 'null' in output
class Node {
int data;
Node next;
Node(int d) { data = d; next = null; }
}
public class LinkedList {
Node head;
public void add(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
} else {
Node temp = head;
while (temp != null) {
temp = temp.next;
}
temp.next = newNode;
}
}
}Solution
Step 1: Analyze the while loop condition
The loop currently runs while temp != null, which moves temp to null and loses reference to last node.Step 2: Correct the loop to stop at last node
The loop should run while temp.next != null to stop at the last node, so we can set temp.next = newNode.Final Answer:
The while loop condition should be 'temp.next != null' instead of 'temp != null' -> Option AQuick Check:
Loop stops at last node using temp.next != null [OK]
- Looping until temp is null loses last node reference
- Creating newNode outside add method is unnecessary
- Adding 'prev' pointer in singly linked list node
Solution
Step 1: Understand adding at head logic
To add at head, new node's next should point to current head, then head updated to new node.Step 2: Check each option's correctness
public void addAtHead(int data) { Node newNode = new Node(data); newNode.next = head; head = newNode; } correctly sets newNode.next = head and then head = newNode. Others incorrectly assign or reverse pointers.Final Answer:
public void addAtHead(int data) { Node newNode = new Node(data); newNode.next = head; head = newNode; } -> Option CQuick Check:
Add at head = newNode.next = head; head = newNode [OK]
- Assigning head.next before updating head
- Reversing pointer assignments
- Overwriting newNode reference incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
