Loading content...
Throughout this module, we've established what non-primitive data structures are, how they enable logical grouping and relationships, and why abstraction is essential. Now it's time to survey the actual terrain—the specific data structures you'll encounter and master throughout this curriculum.
Think of this page as a map of the territory ahead. We won't dive deep into implementation details or complex operations here—dedicated chapters will do that. Instead, we'll establish a clear mental model of each major structure: what it is, what it's for, and where it fits in the broader landscape.
By the end of this page, you'll have a comprehensive overview that will make every subsequent chapter feel like revisiting a familiar friend rather than meeting a stranger.
This page surveys seven fundamental categories of non-primitive data structures: Arrays, Strings, Linked Lists, Stacks, Queues, Trees, and Graphs. For each, you'll learn its essential nature, core use cases, key operations, and trade-offs—providing the conceptual foundation for deep dives to come.
The Array is the most fundamental non-primitive data structure—so fundamental that it's typically built into every programming language and directly supported by hardware.
What Is an Array?
An array is a contiguous block of memory containing a fixed number of elements of the same type. Elements are accessed by their index—a zero-based position number.
Index: 0 1 2 3 4
┌───────┬───────┬───────┬───────┬───────┐
Array: │ 42 │ 17 │ 93 │ 8 │ 56 │
└───────┴───────┴───────┴───────┴───────┘
↑
Base Address
Why Arrays Matter:
| Operation | Time Complexity | Notes |
|---|---|---|
| Access by index | O(1) | Direct calculation from base address |
| Search (unsorted) | O(n) | Must check each element |
| Search (sorted) | O(log n) | Binary search applicable |
| Insert at end | O(1)* | If space available; O(n) if resize needed |
| Insert at position | O(n) | Must shift all subsequent elements |
| Delete at position | O(n) | Must shift all subsequent elements |
Array Variants:
When to Use Arrays:
✅ Need fast random access by position ✅ Collection size is known or changes infrequently ✅ Memory efficiency is important ✅ Sequential processing is common
❌ Frequent insertions/deletions in the middle ❌ Collection size is highly variable ❌ Need fast key-based (not index-based) lookup
Arrays should be your default choice until you have a reason to use something else. Their cache efficiency and simplicity make them faster than theoretically 'better' structures in many real scenarios. A linked list with O(1) insertion is often slower than an array with O(n) insertion due to cache effects.
The String is conceptually an array of characters, but treated as a distinct data structure due to its unique importance and specialized operations.
What Is a String?
A string is an ordered sequence of characters representing text. Unlike a generic array, strings carry semantic meaning and support text-specific operations.
Index: 0 1 2 3 4
┌─────┬─────┬─────┬─────┬─────┐
String: │ H │ e │ l │ l │ o │
└─────┴─────┴─────┴─────┴─────┘
Why Strings Are Special:
| Operation | Time Complexity | Notes |
|---|---|---|
| Access character | O(1) | If fixed-width encoding; O(n) for some UTF encodings |
| Concatenation | O(n+m) | Creates new string of combined length |
| Substring | O(k) | k = substring length; may share memory in some implementations |
| Search (naive) | O(n*m) | n = string length, m = pattern length |
| Search (KMP/Boyer-Moore) | O(n+m) | Advanced algorithms |
| Comparison | O(min(n,m)) | Character-by-character until difference |
String Concepts to Master:
When to Use String-Specific Structures:
✅ Text processing, parsing, formatting ✅ User-facing input and output ✅ File and network operations ✅ When semantic text operations (split, trim, case conversion) are needed
❌ Numeric data that looks like text should be converted to numbers ❌ Binary data should use byte arrays, not strings
Strings seem simple until you encounter Unicode. A 'character' might be one byte (ASCII), two bytes (some UTF-16), or four bytes (many emojis). String length might differ from byte count, display width, and grapheme cluster count. String processing in a globalized world requires understanding these distinctions.
The Linked List sacrifices array's random access for flexible insertion and deletion, using pointers to connect elements scattered in memory.
What Is a Linked List?
A linked list is a sequence of nodes, each containing data and a reference (pointer) to the next node. Elements are not contiguous—they can be anywhere in memory.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Data: 42 │ │ Data: 17 │ │ Data: 93 │
│ Next: ───────┼───→│ Next: ───────┼───→│ Next: null │
└──────────────┘ └──────────────┘ └──────────────┘
Head Tail
Linked List Variants:
| Operation | Singly Linked | Doubly Linked | Notes |
|---|---|---|---|
| Access by index | O(n) | O(n) | Must traverse from head or tail |
| Insert at head | O(1) | O(1) | Just update pointers |
| Insert at tail | O(1)* | O(1) | *O(1) with tail pointer |
| Insert at position | O(n) | O(n) | O(1) if position known |
| Delete by reference | O(n)/O(1) | O(1) | Singly: need previous; Doubly: immediate |
| Search | O(n) | O(n) | Must traverse |
Linked List Trade-offs:
Advantages:
Disadvantages:
When to Use Linked Lists:
✅ Frequent insertions/deletions at ends ✅ Implementing stacks, queues, deques ✅ When you need to insert/delete without shifting ✅ When memory is fragmented
❌ Need fast random access ❌ Cache efficiency matters ❌ Memory overhead is a concern
In theory, linked lists shine with O(1) insertions. In practice, cache misses make each pointer traversal expensive (100+ cycles vs 1 cycle for sequential array access). Profile before choosing linked lists over arrays—the 'slower' array is often faster.
The Stack is not just a data structure—it's a behavioral constraint. It restricts how elements are added and removed, modeling many real-world patterns.
What Is a Stack?
A stack is a Last-In, First-Out (LIFO) structure where elements are added and removed from the same end (the 'top'). Think of a stack of plates: you can only add to or take from the top.
┌───────┐
Top → │ 56 │ ← Most recently added
├───────┤
│ 8 │
├───────┤
│ 93 │
├───────┤
Bottom → │ 42 │ ← First added (last to be removed)
└───────┘
Core Stack Operations:
push(item) — Add item to toppop() — Remove and return top itempeek()/top() — Return top item without removingisEmpty() — Check if stack is emptyAll operations are O(1) in any reasonable implementation.
Why Stacks Matter — Use Cases:
Stack Implementations:
Both provide O(1) for all operations. Array-based is usually preferred for cache efficiency.
When to Use Stacks:
✅ LIFO access pattern is required ✅ Managing nested structures (recursion, scopes, tags) ✅ Backtracking algorithms ✅ Undo functionality
❌ Need access to elements other than top ❌ Need FIFO (use queue instead) ❌ Need random access
Every recursive algorithm implicitly uses the call stack. You can convert any recursive algorithm to iterative by explicitly managing a stack. Understanding stacks deeply means understanding recursion deeply, and vice versa.
The Queue models a different behavioral constraint: fairness. The first to arrive is the first to be served.
What Is a Queue?
A queue is a First-In, First-Out (FIFO) structure where elements are added at one end (the 'rear') and removed from the other (the 'front'). Think of a line at a ticket counter.
Dequeue Enqueue
↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│Front: 42│ → │ 17 │ → │ 93 │ → │Rear: 56 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
Core Queue Operations:
enqueue(item) / offer(item) — Add item to reardequeue() / poll() — Remove and return front itempeek() / front() — Return front item without removingisEmpty() — Check if queue is emptyAll operations are O(1) in proper implementations.
Why Queues Matter — Use Cases:
Queue Variants:
Queue Implementations:
When to Use Queues:
✅ FIFO processing required ✅ Order of arrival matters ✅ Buffering between producer and consumer ✅ BFS and level-order traversals
❌ Need access to arbitrary elements ❌ Need LIFO (use stack) ❌ Need priority-based processing (use priority queue)
This is one of the most important mental models in algorithms. BFS explores level-by-level using a queue (process all neighbors before going deeper). DFS explores depth-first using a stack (go as deep as possible before backtracking). The only difference is the data structure—the algorithm logic is nearly identical.
Trees model hierarchical relationships—structures where entities have parent-child connections forming a branching pattern.
What Is a Tree?
A tree is a connected, acyclic graph with:
[ROOT]
/ | \
[A] [B] [C]
/ \ |
[D] [E] [F]
/ \
[G] [H]
Tree Terminology:
Why Trees Matter:
Trees naturally model countless real-world structures:
Important Tree Variants:
| Operation | Complexity | Notes |
|---|---|---|
| Search | O(log n) | Binary search principle |
| Insert | O(log n) | Find position, add node, rebalance |
| Delete | O(log n) | Find node, restructure, rebalance |
| Find Min/Max | O(log n) | Follow leftmost/rightmost path |
| Traversal (in-order, pre-order, post-order) | O(n) | Visit all nodes |
The magic of trees comes from halving the search space at each level. A balanced tree with n nodes has height ~log₂(n). 1 million nodes? Just 20 levels. 1 billion? About 30. This logarithmic efficiency is why trees underpin databases, file systems, and search engines.
Graphs are the most general relationship structure—capable of representing any pattern of connections between entities.
What Is a Graph?
A graph consists of:
Unlike trees, graphs have no restrictions on connectivity:
[A] ←——→ [B]
↑ ↓
| [C] ←——→ [D]
↓ |
[E] ←—————┘
Graph Characteristics:
Real-World Graph Examples:
Graph Representations:
| Algorithm | Purpose | Complexity |
|---|---|---|
| BFS | Level-order traversal, shortest path (unweighted) | O(V + E) |
| DFS | Explore paths, detect cycles, topological sort | O(V + E) |
| Dijkstra | Shortest path (weighted, non-negative) | O((V + E) log V) |
| Bellman-Ford | Shortest path (handles negative weights) | O(VE) |
| A* | Shortest path with heuristic | Varies by heuristic |
| Topological Sort | Order DAG respecting dependencies | O(V + E) |
| Union-Find | Check connectivity, find components | O(α(n)) per operation |
Arrays, linked lists, and trees are all special cases of graphs. An array is a linear graph. A tree is an acyclic connected graph with a root. Understanding graphs means understanding the most general form of data relationships.
With all these structures in mind, how do you choose the right one? Here's a decision framework:
Step 1: Identify the Relationship Type
Step 2: Identify Critical Operations
Step 3: Consider Constraints
| If You Need... | Consider... |
|---|---|
| Fast random access by index | Array, dynamic array |
| Fast insertion/deletion at ends | Deque, circular buffer |
| LIFO access | Stack |
| FIFO access | Queue |
| Fast key-value lookup (unordered) | Hash table |
| Ordered key-value with range queries | Balanced BST, skip list |
| Priority-based access | Heap / Priority queue |
| Prefix-based string operations | Trie |
| Hierarchical data | Tree |
| Arbitrary connections, path finding | Graph |
When unsure, start with the simplest structure that works (often an array or hash table). Optimize only when you have evidence of performance problems. Premature optimization with complex structures often backfires—the 'better' structure is slower due to overhead and worse cache behavior.
This page has provided a bird's-eye view of the non-primitive data structure landscape. The chapters ahead will dive deep into each:
Chapter 4: Strings — Deep exploration of string representation, operations, pattern matching, and algorithms.
Chapter 5: Arrays — Memory model, static vs dynamic arrays, two-pointer techniques, sliding windows, multi-dimensional arrays.
Chapter 6: Linked Lists — Node-based thinking, singly vs doubly linked, circular variants, two-pointer techniques for lists.
Chapter 7: Stacks — Implementation patterns, expression evaluation, parsing applications, monotonic stacks.
Chapter 8: Queues — Circular queues, deques, priority queues, queue-based algorithms.
Chapters 11-15: Trees — Binary trees, BSTs, balanced trees (AVL, Red-Black), heaps, tries.
Chapters 16, 23-24: Graphs — Representation, traversal, shortest paths, spanning trees, advanced algorithms.
The Learning Strategy:
For each structure, you'll learn:
This consistent framework will help you build a coherent mental model where each structure is connected to the others, not isolated.
You now have a map of the territory. Every subsequent chapter fills in details on this map. When you learn about AVL trees, you'll know they're balanced BST variants for O(log n) guarantees. When you encounter Dijkstra's algorithm, you'll know it operates on weighted graphs. This context makes learning faster and more meaningful.
Let's consolidate our survey of non-primitive data structures:
Module Complete:
This concludes Module 5: Non-Primitive Data Structures (Conceptual Overview). You now understand:
With this foundation, you're prepared to dive deep into each structure in the chapters ahead, understanding not just how they work but why they're designed the way they are.
Congratulations! You've completed the conceptual foundation for non-primitive data structures. You are now equipped with the mental framework to understand every data structure this curriculum will cover. The deep dives begin with the next chapter.