Create a Circular Singly Linked List in DSA Typescript - Time & Space Complexity
When we create a circular singly linked list, we want to know how the time needed grows as we add more nodes.
We ask: How long does it take to build this list as it gets bigger?
Analyze the time complexity of the following code snippet.
class Node {
value: number;
next: Node | null = null;
constructor(value: number) {
this.value = value;
}
}
function createCircularList(arr: number[]): Node | null {
if (arr.length === 0) return null;
const head = new Node(arr[0]);
let current = head;
for (let i = 1; i < arr.length; i++) {
current.next = new Node(arr[i]);
current = current.next;
}
current.next = head; // Make it circular
return head;
}
This code creates a circular singly linked list from an array of numbers by linking nodes in order and connecting the last node back to the first.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The for-loop that creates and links each new node.
- How many times: It runs once for each element after the first, so (n - 1) times if n is the array length.
As the input array grows, the number of steps to create nodes and link them grows roughly the same way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 9 node creations and links |
| 100 | About 99 node creations and links |
| 1000 | About 999 node creations and links |
Pattern observation: The work grows linearly with the number of elements; doubling the input roughly doubles the work.
Time Complexity: O(n)
This means the time to create the circular list grows in direct proportion to the number of elements.
[X] Wrong: "Creating a circular list takes constant time because we just link the last node to the head once."
[OK] Correct: While linking the last node to the head is one step, creating and linking all the nodes before that takes time proportional to the number of elements.
Understanding how creating linked lists scales helps you explain your code clearly and shows you know how data grows in real programs.
"What if we changed the input from an array to a linked list and created a circular list by traversing it? How would the time complexity change?"
Practice
Solution
Step 1: Understand the structure of a circular singly linked list
In a circular singly linked list, the last node's next pointer points back to the first node, creating a loop.Step 2: Compare with other list types
Regular singly linked lists end with a null pointer, doubly linked lists have two pointers per node, and arrays are not linked lists.Final Answer:
The last node points back to the first node, forming a circle. -> Option AQuick Check:
Circular list last node points to head = A [OK]
- Thinking circular means doubly linked
- Assuming last node points to null
- Confusing arrays with linked lists
Solution
Step 1: Understand initialization of circular singly linked list
For an empty circular singly linked list with one node, the node's next pointer should point to itself.Step 2: Analyze each option
let head: Node = new Node(null); head.next = head; creates a node and sets its next to itself, correctly forming a circular list with one node. let head: Node | null = null; sets head to null (empty list, but not circular). let head: Node | null = new Node(null); head.next = null; sets next to null (not circular). let head: Node = null; head.next = head; tries to assign next on null (error).Final Answer:
let head: Node = new Node(null); head.next = head; -> Option DQuick Check:
One node points to itself = A [OK]
- Setting next to null instead of self
- Assigning next on null variable
- Not creating a node before linking
class Node {
value: number;
next: Node | null;
constructor(value: number) {
this.value = value;
this.next = null;
}
}
class CircularList {
head: Node | null = null;
insert(value: number) {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
newNode.next = this.head;
} else {
let temp = this.head;
while (temp.next !== this.head) {
temp = temp.next!;
}
temp.next = newNode;
newNode.next = this.head;
}
}
print() {
if (!this.head) return '';
let result = '';
let temp = this.head;
do {
result += temp.value + ' -> ';
temp = temp.next!;
} while (temp !== this.head);
result += 'null';
return result;
}
}
const list = new CircularList();
list.insert(1);
list.insert(2);
list.insert(3);
console.log(list.print());Solution
Step 1: Trace insertions and list structure
Insert 1: head points to node 1, node 1 next points to itself.
Insert 2: find last node (1), set last node's next to new node 2, new node 2 next points to head (1).
Insert 3: find last node (2), set last node's next to new node 3, new node 3 next points to head (1).Step 2: Trace print method output
Print starts at head (1), prints 1 -> 2 -> 3 -> then stops when it reaches head again, appends 'null'.Final Answer:
1 -> 2 -> 3 -> null -> Option CQuick Check:
Print stops at head, adds null = B [OK]
- Printing extra head node again
- Missing 'null' at end
- Infinite loop without stopping condition
insert(value: number) {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
newNode.next = null;
} else {
let temp = this.head;
while (temp.next !== this.head) {
temp = temp.next!;
}
temp.next = newNode;
newNode.next = this.head;
}
}Solution
Step 1: Analyze insertion when list is empty
When the list is empty, newNode.next is set to null, breaking circular property. It should point to head to form a circle.Step 2: Check loop condition and other logic
The while loop correctly finds the last node by checking temp.next !== head. Other parts are correct.Final Answer:
newNode.next should point to head, not null, when list is empty. -> Option BQuick Check:
Empty list node next must point to itself = C [OK]
- Setting next to null breaks circular link
- Wrong loop condition causes infinite loop
- Resetting head incorrectly
delete(value: number) to remove a node with a given value from a circular singly linked list. Which approach correctly handles deleting the head node while maintaining the circular structure?Solution
Step 1: Understand deleting head in circular list
To delete the head, we must update the last node's next pointer to the new head (head.next) to maintain the circle.Step 2: Analyze each option
Find the last node, set its next to head.next, then update head to head.next. correctly finds last node, updates its next to head.next, then moves head to head.next.
Set head to null directly without updating any other node. breaks the list by setting head to null without fixing last node.
Set head.next to null and keep head unchanged. breaks the circle by setting head.next to null.
Remove the node by setting head to head.next without updating last node's next. moves head but leaves last node pointing to old head, breaking the circle.Final Answer:
Find the last node, set its next to head.next, then update head to head.next. -> Option AQuick Check:
Last node next updated to new head = D [OK]
- Not updating last node's next pointer
- Setting head to null without cleanup
- Breaking circular link by null assignments
Ready to prove it?
Pass the test and this pattern moves unknown
