Which scenario best explains when a linked list is a better choice than an array?
Think about which data structure allows easy insertion and deletion without shifting many elements.
Linked lists allow fast insertion and deletion anywhere because they only change pointers, unlike arrays which require shifting elements.
What is the output after inserting 99 at index 1 in both an array and a linked list?
Array starts as [10, 20, 30]
Linked list starts as 10 -> 20 -> 30 -> null
const array = [10, 20, 30]; array.splice(1, 0, 99); class Node { constructor(value) { this.value = value; this.next = null; } } class LinkedList { constructor() { this.head = null; } append(value) { const newNode = new Node(value); if (!this.head) { this.head = newNode; return; } let current = this.head; while (current.next) { current = current.next; } current.next = newNode; } insertAt(index, value) { const newNode = new Node(value); if (index === 0) { newNode.next = this.head; this.head = newNode; return; } let current = this.head; let prev = null; let i = 0; while (current && i < index) { prev = current; current = current.next; i++; } prev.next = newNode; newNode.next = current; } toString() { let result = ''; let current = this.head; while (current) { result += current.value + ' -> '; current = current.next; } return result + 'null'; } } const list = new LinkedList(); [10, 20, 30].forEach(v => list.append(v)); list.insertAt(1, 99); console.log('Array:', array); console.log('LinkedList:', list.toString());
Remember that array.splice(index, 0, value) inserts at index shifting elements right.
Linked list insertion at index 1 places new node after first node.
Array.splice inserts 99 at index 1 shifting 20 and 30 right. Linked list insertion at index 1 places 99 after 10.
Consider this code to delete a node with value 3 from a linked list. Why does it fail to delete the node?
class Node { constructor(value) { this.value = value; this.next = null; } } class LinkedList { constructor() { this.head = null; } append(value) { const newNode = new Node(value); if (!this.head) { this.head = newNode; return; } let current = this.head; while (current.next) { current = current.next; } current.next = newNode; } delete(value) { let current = this.head; while (current) { if (current.value === value) { current = current.next; return; } current = current.next; } } }
Think about what is needed to remove a node from a linked list.
To delete a node, you must update the previous node's next pointer to skip the node to delete. This code only moves the current pointer, so the list remains unchanged.
Given an array and a linked list both containing [5, 10, 15, 20, 25], what is the time complexity to access the element at index 3?
What is the output of accessing that element?
const array = [5, 10, 15, 20, 25]; class Node { constructor(value) { this.value = value; this.next = null; } } class LinkedList { constructor() { this.head = null; } append(value) { const newNode = new Node(value); if (!this.head) { this.head = newNode; return; } let current = this.head; while (current.next) { current = current.next; } current.next = newNode; } getAt(index) { let current = this.head; let i = 0; while (current && i < index) { current = current.next; i++; } return current ? current.value : null; } } const list = new LinkedList(); [5, 10, 15, 20, 25].forEach(v => list.append(v)); const arrayValue = array[3]; const listValue = list.getAt(3); console.log('Array element at index 3:', arrayValue); console.log('LinkedList element at index 3:', listValue);
Arrays allow direct access by index. Linked lists require walking nodes one by one.
Accessing an array element by index is fast (constant time). Accessing a linked list element requires traversing nodes (linear time). Both return the value 20 at index 3.
You are designing a system that requires frequent insertions and deletions at unknown positions and must use memory efficiently without fragmentation. Which data structure is best?
Consider which structure avoids memory fragmentation and supports dynamic size with efficient insert/delete.
Linked lists allocate memory dynamically for each node, avoiding fragmentation and allowing efficient insertions/deletions anywhere without shifting elements.
