Imagine you have a list of items that can grow or shrink often. Which problem does a linked list solve better than an array?
Think about what happens when you add or remove items in the middle of an array.
Arrays store elements in continuous memory, so inserting or deleting in the middle requires shifting elements, which is slow. Linked lists use nodes connected by pointers, so insertion and deletion anywhere is quick without shifting.
What is the printed state of the linked list after these insertions?
class Node { value: number; next: Node | null = null; constructor(value: number) { this.value = value; } } class LinkedList { head: Node | null = null; insertAtHead(value: number) { const newNode = new Node(value); newNode.next = this.head; this.head = newNode; } printList() { let current = this.head; let result = ''; while (current) { result += current.value + ' -> '; current = current.next; } result += 'null'; console.log(result); } } const list = new LinkedList(); list.insertAtHead(3); list.insertAtHead(5); list.insertAtHead(7); list.printList();
Remember that insertAtHead adds new nodes at the start of the list.
Each new value is added at the head, so the last inserted value is first in the list. The order is 7 (last inserted), then 5, then 3.
What error does this code cause when inserting a node, and why?
class Node { value: number; next: Node | null = null; constructor(value: number) { this.value = value; } } class LinkedList { head: Node | null = null; insertAtTail(value: number) { const newNode = new Node(value); if (!this.head) { this.head = newNode; } else { let current = this.head; while (current.next) { current = current.next; } current.next = newNode; } } printList() { let current = this.head; let result = ''; while (current) { result += current.value + ' -> '; current = current.next; } result += 'null'; console.log(result); } } const list = new LinkedList(); list.insertAtTail(1); list.insertAtTail(2); list.insertAtTail(3); list.insertAtTail(null as any); list.printList();
Look at what happens when inserting null as a node value and how the code handles it.
Inserting null as a value creates a node with null value but valid next pointer. The code does not check for null values, so no error on insertion. However, if null is cast incorrectly or used as a node, it can cause a TypeError when accessing next on null. Here, the cast null as any bypasses type safety but the node is created. The error occurs if code tries to access next of null directly, which can happen if the list is corrupted.
What is the linked list state after removing the node with value 2?
class Node { value: number; next: Node | null = null; constructor(value: number) { this.value = value; } } class LinkedList { head: Node | null = null; insertAtTail(value: number) { const newNode = new Node(value); if (!this.head) { this.head = newNode; } else { let current = this.head; while (current.next) { current = current.next; } current.next = newNode; } } remove(value: number) { if (!this.head) return; if (this.head.value === value) { this.head = this.head.next; return; } let current = this.head; while (current.next && current.next.value !== value) { current = current.next; } if (current.next) { current.next = current.next.next; } } printList() { let current = this.head; let result = ''; while (current) { result += current.value + ' -> '; current = current.next; } result += 'null'; console.log(result); } } const list = new LinkedList(); list.insertAtTail(1); list.insertAtTail(2); list.insertAtTail(3); list.remove(2); list.printList();
Think about how the remove method updates the links to skip the removed node.
The remove method finds the node before the one with value 2 and changes its next pointer to skip the node with value 2, effectively removing it. The list becomes 1 -> 3 -> null.
Which reason best explains why linked lists are often used to implement stacks and queues instead of arrays?
Consider what happens when a stack or queue grows beyond the initial array size.
Stacks and queues often grow or shrink dynamically. Arrays require resizing and copying when full, which is costly. Linked lists grow dynamically by adding nodes without resizing or copying, making them efficient for these data structures.
