Hello! Welcome to your fourth lesson on core data structures.
In the past two lessons, you implemented the fundamental building blocks of linked lists: creating the structure, traversing it, and performing insertions and deletions. You've seen how these operations work by manipulating pointers.
Today, we take a step back to answer a critical question you'll face in any system design or algorithm interview: when should you use a linked list, and when is an array the better choice? The goal of this lesson is to explain the use cases and performance characteristics of arrays vs. linked lists. Understanding these trade-offs is not just about memorizing complexities; it's about demonstrating your ability to make informed decisions about data structures based on the problem at hand.
1. The Fundamental Difference: Memory Layout
Almost every difference between arrays and linked lists stems from how they store data in memory.
- Arrays store elements in a contiguous block of memory. Think of a row of adjacent numbered mailboxes.
- Linked Lists store elements in non-contiguous memory. Each element (a node) contains the data and a pointer (an address) to the next node. Think of a scavenger hunt where each clue tells you where to find the next one.

This single difference has profound implications for performance.
2. Performance Deep Dive: Operations and Complexity
Let's break down the performance of common operations. For a fantastic and clear explanation of these trade-offs, start by watching this video.
Data Structures: Arrays vs Linked Lists
The video 'Data Structures: Arrays vs Linked Lists' from mycodeschool provides a comprehensive comparison of arrays and linked lists across key operations.
Please watch from 01:04 to 11:30. The video covers: Accessing an element (01:04) Memory requirements (04:26) Insertion costs (08:25) Pay close attention to the 'why' behind each time complexity.
Let's summarize and expand on the key points from the video.
| Operation | Dynamic Array | Singly Linked List | Why? |
|---|---|---|---|
| Access (by index) | Array: You can calculate the memory address directly (base_address + index * element_size). List: You must traverse from the head, following n pointers to get to the nth element. |
||
| Search (by value) | Both require a linear scan if unsorted. However, a sorted array can be searched in time using binary search, an option unavailable to linked lists. | ||
| Insertion (at beginning) | Array: All other elements must be shifted one position to the right. List: You only update the head pointer and the new node's next pointer. |
||
| Insertion (at end) | * | ** | Array: If there's spare capacity, it's just one assignment. (*Amortized ; worst-case is if a resize is needed). List: You must traverse to the last node to update its next pointer. (**Can be if you maintain a tail pointer). |
| Insertion (in middle) | Array: Requires shifting elements. List: Requires traversing to find the insertion point. However, the insertion itself is a quick pointer update once you're there. |
||
| Deletion (from beginning) | Array: All other elements must be shifted left. List: You just move the head pointer to the next node. |
||
| Deletion (from end) | Array: It's a simple index update. List: You must traverse to find the second-to-last node to update its next pointer to None. |

3. Practical Performance: Cache Locality
So far, we've focused on theoretical time complexity. In an interview with a top company, showing you understand the practical hardware implications can set you apart. This is where your computer architecture knowledge comes into play.
Modern CPUs rely heavily on caching to speed up memory access. When a CPU reads from memory, it doesn't just fetch one byte; it pulls in a whole "cache line" (e.g., 64 bytes). The principle of spatial locality states that if you access a memory location, you are very likely to access nearby locations soon.
- Arrays are a perfect example of spatial locality. Because elements are contiguous, when you fetch the first element, the next several are likely pulled into the cache simultaneously. This makes iterating through an array incredibly fast.
- Linked Lists have poor spatial locality. Nodes can be scattered all over memory. Accessing
node.nextcan result in a cache miss, forcing the CPU to fetch data from a completely different memory location, which is significantly slower.
Arrays vs. Linked Lists: Key Differences & Use Cases
The article 'Arrays vs. Linked Lists' from The Coder Cafe has an excellent section that discusses why linked lists can be slower in practice despite their theoretical advantages.
Read the section that starts with 'Despite their theoretical advantages...'. Focus on the concepts of spatial locality, cache misses, and CPU prefetching. This connects the abstract data structure to real-world hardware performance.
The takeaway is that even though iterating through an array and a linked list are both operations, the array version is almost always faster in practice due to being more cache-friendly.
4. Memory Usage and Overhead
The trade-offs continue when we consider memory.
- Dynamic Arrays:
- Pro: No per-element overhead. An array of 1000 integers uses the space for exactly 1000 integers.
- Con: May have wasted space. A dynamic array often doubles its capacity when it runs out of room. If you have 501 elements, your array might have allocated space for 1000, wasting nearly half.
- Linked Lists:
- Pro: No wasted space. Memory is allocated on a per-node basis as needed.
- Con: Per-element overhead. Each node must store at least one pointer in addition to the data. In a 64-bit system, a pointer takes 8 bytes. If you're storing 4-byte integers, you're more than tripling the memory usage for each element! However, if you're storing large objects, this pointer overhead becomes negligible.
Test your understanding!
You are designing a system to manage user actions for an "undo" feature in a text editor. Actions are added frequently and are always undone in a last-in, first-out order. Performance is critical. Would you choose a dynamic array or a linked list? Justify your choice based on the primary operations.
Show answer
A linked list would be the better choice. The primary operations are adding a new action (to the front of the list) and removing the most recent action (also from the front).
- Insertion: Adding an action is an
insert_at_beginningoperation, which is for a linked list but for a dynamic array. - Deletion: The "undo" action is a
delete_from_beginningoperation, which is also for a linked list but for a dynamic array.
Since all critical operations happen at the head of the sequence, the linked list's performance for these specific operations makes it far more suitable than an array. There is no need for random access.
5. Summary: When to Use Which?
Here is a simple decision framework for your interviews:
Choose a Dynamic Array if:
- You need frequent and fast random access to elements (e.g.,
get(i)). - The primary operations are appending or removing from the end.
- The size of the collection is relatively stable, or you can make a good initial size estimate.
- Iteration performance is critical (leveraging the cache is important).
Common Use Cases: Storing a list of items to be accessed by index, used as the underlying structure for other data structures like heaps.
Choose a Linked List if:
- You need frequent and fast insertions and deletions at the beginning or middle of the list.
- You cannot predict the size of the list, and it will grow and shrink dynamically.
- You are implementing a queue or a stack (especially a queue, to avoid the cost of removing from an array's front).
- The memory overhead of pointers is acceptable compared to the potential waste of an array's unused capacity.
Common Use Cases: Music playlists (inserting/deleting songs anywhere), undo/redo functionality, chaining in hash tables to resolve collisions, implementing queues. The article "Linked List Interview Questions & Tips for Senior Engineers" which we used in a previous lesson provides a great summary of these use cases in its section "When to Use Linked Lists in Interviews".
Conclusion
You are now equipped not just to implement arrays and linked lists, but to defend your choice of one over the other—a crucial skill for any technical interview.
Key Takeaways:
- The core trade-off is Access vs. Modification: Arrays excel at fast, indexed access (), while linked lists excel at fast insertions/deletions at the beginning ().
- Memory Structure is Key: Contiguous (array) vs. non-contiguous (linked list) memory layout dictates performance.
- Theory vs. Practice: Arrays are often faster for iteration in the real world due to cache locality, even when complexities are the same on paper.
- Memory Cost: Arrays can waste space with unused capacity, while linked lists have a per-element overhead for pointers.
In our next lesson, we will move on to another fundamental sequential data structure: strings. We will explore how to implement common string manipulation operations and transformations efficiently, a topic rich with its own unique set of interview problems and patterns.