Why Linked List Exists and What Problem It Solves in DSA Typescript - Performance Analysis
We want to understand why linked lists are useful by looking at how fast they work for certain tasks.
What problem do linked lists solve compared to other ways to store data?
Analyze the time complexity of adding an element at the start of a linked list.
class Node {
value: number;
next: Node | null = null;
constructor(value: number) {
this.value = value;
}
}
class LinkedList {
head: Node | null = null;
addFirst(value: number) {
const newNode = new Node(value);
newNode.next = this.head;
this.head = newNode;
}
}
This code adds a new item at the beginning of a linked list quickly by changing just a few pointers.
Look for loops or repeated steps that take time.
- Primary operation: Adding a node at the start involves only a few steps, no loops.
- How many times: Always the same small number of steps, no matter how big the list is.
Adding at the start takes the same time whether the list has 10 or 1000 items.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 3 steps (create node, link, update head) |
| 100 | 3 steps (same as above) |
| 1000 | 3 steps (still the same) |
Pattern observation: The time to add at the start does not grow with the list size; it stays constant.
Time Complexity: O(1)
This means adding at the start takes a fixed amount of time, no matter how big the list is.
[X] Wrong: "Adding an item to a linked list always takes longer as the list grows."
[OK] Correct: Adding at the start only changes a few pointers, so it takes the same time regardless of list size.
Knowing why linked lists exist and how fast they add or remove items helps you explain data structure choices clearly in interviews.
"What if we changed addFirst to addLast (adding at the end)? How would the time complexity change?"
Practice
Solution
Step 1: Understand array limitations
Arrays store elements in continuous memory, so inserting or deleting in the middle requires shifting many elements, which is slow.Step 2: Understand linked list advantage
Linked lists store elements as nodes with pointers, so insertion or deletion only changes pointers without shifting elements.Final Answer:
Because linked lists allow easy insertion and deletion without shifting elements -> Option AQuick Check:
Linked list insertion/deletion = easy [OK]
- Thinking linked lists always use less memory
- Believing linked lists store elements contiguously
- Assuming linked lists have fast random access
Solution
Step 1: Check next pointer type
In a singly linked list, next can be another Node or null if it's the last node.Step 2: Verify constructor initialization
The constructor sets value and initializes next to null correctly.Final Answer:
class Node { value: number; next: Node | null; constructor(value: number) { this.value = value; this.next = null; } } -> Option AQuick Check:
Node next type = Node or null [OK]
- Not allowing next to be null
- Setting next to undefined instead of null
- Using any type for next pointer
class Node {
value: number;
next: Node | null;
constructor(value: number) {
this.value = value;
this.next = null;
}
}
const head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
let current = head;
const values: number[] = [];
while (current !== null) {
values.push(current.value);
current = current.next;
}
console.log(values);Solution
Step 1: Build linked list nodes
Nodes created with values 1, 2, 3 linked in order: 1 -> 2 -> 3 -> null.Step 2: Traverse linked list and collect values
Loop visits nodes in order: 1, then 2, then 3, pushing values into array.Final Answer:
[1, 2, 3] -> Option DQuick Check:
Traversal order = [1, 2, 3] [OK]
- Confusing order and reversing output
- Stopping traversal too early
- Not initializing next pointers correctly
class Node {
value: number;
next: Node | null;
constructor(value: number) {
this.value = value;
this.next = null;
}
}
const head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
function insertAtEnd(head: Node, value: number) {
let current = head;
while (current.next !== null) {
current = current.next;
}
current = new Node(value);
}
insertAtEnd(head, 4);
let current = head;
const values: number[] = [];
while (current !== null) {
values.push(current.value);
current = current.next;
}
console.log(values);Solution
Step 1: Analyze insertion logic
The code moves current to last node, but then assigns current = new Node(value), which only changes local variable, not the list.Step 2: Correct pointer assignment
To link new node, must assign current.next = new Node(value) so last node points to new node.Final Answer:
The new node is not linked to the last node; assignment should be current.next = new Node(value) -> Option BQuick Check:
Link new node with current.next = new Node(value) [OK]
- Assigning new node to current variable only
- Wrong loop condition causing null errors
- Expecting function to return new head unnecessarily
Solution
Step 1: Understand operation needs
Adding/removing tasks often in the middle means many insertions and deletions not at the end.Step 2: Compare array vs linked list for middle operations
Arrays require shifting elements on insert/delete in middle, which is slow. Linked lists only change pointers, so faster for these operations.Final Answer:
Linked list, because it allows efficient insertion and deletion in the middle without shifting elements -> Option CQuick Check:
Middle insert/delete = linked list best [OK]
- Choosing array for fast random access ignoring insert/delete cost
- Thinking linked lists use less memory always
- Believing linked lists store elements contiguously
Ready to prove it?
Pass the test and this pattern moves unknown
