codeworking.org
Search
Course Syllabus (Lesson 02 of 03)
Algorithms & Data Structures Mastery • Module 01 15 min read

Deep Dive: Introduction to Data Structures & Physical Memory Models

1. What is a Data Structure?

While an algorithm defines the instructions and logic of computation, a data structure is the physical and logical arrangement of data in computer memory designed to enable efficient access, mutation, and traversal.

┌─────────────────────────────────────────────────────────────────────────────┐
│                          THE COMPUTING DUALITY                              │
├──────────────────────────────────────┬──────────────────────────────────────┤
│              ALGORITHM               │            DATA STRUCTURE            │
│       (Verbs: What to execute)       │        (Nouns: What to manipulate)   │
├──────────────────────────────────────┼──────────────────────────────────────┤
│ • State transitions                  │ • Memory address layout              │
│ • Decision logic & loops             │ • Pointer & index relationships      │
│ • Step-by-step procedure             │ • Contiguous vs fragmented topology  │
└──────────────────────────────────────┴──────────────────────────────────────┘

Every data structure represents a specific engineering tradeoff between four core access patterns:

  1. Direct Indexing: Can we jump directly to the k-th item in O(1) time?
  2. Insertion & Deletion: Can we add or remove items without shifting existing elements in memory?
  3. Search & Lookup: How fast can we determine if a value exists?
  4. Memory Overhead: How many auxiliary bytes (pointers, metadata, headers) are required per byte of payload data?

2. Physical RAM Architecture & Byte Addressability

To understand why data structures perform the way they do, we must discard the abstraction of high-level code and look at the physical silicon hardware.

Physical RAM (Random Access Memory) is structured as a vast, continuous, linear sequence of 1-byte storage cells (8 bits), where each byte possesses a unique 64-bit integer address:

Address: 0x1000   0x1001   0x1002   0x1003   0x1004   0x1005   0x1006   0x1007
Byte:   [ 0xFF ] [ 0x00 ] [ 0x12 ] [ 0xA4 ] [ 0x00 ] [ 0x00 ] [ 0x00 ] [ 0x01 ]
         └───────────────────────────────────┴──────────────────────────────────┘
                      64-Bit Integer (8 Bytes contiguous in RAM)

The Math of Direct Array Indexing

When you declare an array of 32-bit integers (int32_t arr[1000]), the compiler allocates a single contiguous block of 1000 * 4 = 4,000 bytes in RAM.

Because every element is identical in size, the CPU computes the exact memory address of any element i using a single hardware multiplication:

Address(arr[i]) = Base_Address + (i * Size_Of_Element)
// Direct memory offset calculation:
// Base Address = 0x2000
// Size of int32 = 4 bytes
// arr[5] Address = 0x2000 + (5 * 4) = 0x2014

This simple hardware formula is the reason why array indexing is universally O(1).


3. The Memory Wall & The CPU Cache Hierarchy

While CPU processing speeds have accelerated exponentially according to Moore’s Law, memory bus latency to physical DRAM has lagged significantly behind. This divergence is known in computer engineering as the Memory Wall.

L1 Cache
~0.5 - 1.0 ns
On-core SRAM (32-64 KB). Instant execution speed.
L2 Cache
~3 - 4 ns
Dedicated core SRAM (512 KB - 1 MB). Extremely fast.
L3 Cache
~10 - 15 ns
Shared on-die SRAM (16 - 96 MB). High capacity.
Physical RAM
~60 - 100 ns
External DRAM chips. The CPU stalls 200+ cycles during fetch!

When the CPU requests data from an address in RAM that is not present in the cache (a Cache Miss), the CPU must idle for 200+ clock cycles waiting for electrons to traverse the motherboard memory bus.


4. Cache Lines & The Two Principles of Locality

The CPU memory controller never fetches a single isolated byte from RAM. Instead, it always fetches a fixed 64-byte chunk known as a Cache Line.

Memory Bus Fetch Request:
[ Byte 0 | Byte 1 | Byte 2 | ... | Byte 62 | Byte 63 ] (64 Bytes loaded into L1)

Modern data structure design is governed by two physical laws:

1. Spatial Locality (Memory Proximity)

If you access memory at address A, you are overwhelmingly likely to access address A + 1 immediately next.

Example: When you iterate through a contiguous array of 32-bit integers (4 bytes each), loading the first element (arr[0]) into the CPU automatically pulls the next 15 integers (arr[1] through arr[15]) into the ultra-fast L1 cache for free!

2. Temporal Locality (Time Proximity)

If you access memory at address A, you are overwhelmingly likely to access the exact same address again in the near future.

Example: Loop counters and accumulator variables remain in L1 registers throughout loop execution.


5. Contiguous Memory (Arrays) vs Pointer-Linked Memory (Linked Lists)

Let us examine the two fundamental topologies used to store a collection of N items:

Contiguous Array Layout
[ Item 0 ][ Item 1 ][ Item 2 ][ Item 3 ]
• Single allocated block in RAM.
• Perfect spatial locality (0 cache misses).
• Fixed size (resizing requires reallocation).
Pointer-Linked Node Layout
[Node0]-> [Node1]-> [Node2]
• Scattered heap allocations.
• Poor spatial locality (cache miss per hop).
• Dynamic size with 8-byte pointer overhead per node.

The Benchmark Paradox: Why Arrays Outperform Linked Lists by 50x

In theoretical asymptotic analysis, both an Array iteration and a Linked List traversal have identical time complexity:

Array Iteration:        O(n) Time
Linked List Traversal:  O(n) Time

Yet, if you run a benchmark iterating over 10,000,000 integers:

  • Contiguous Array Scan: ~2.1 milliseconds
  • Linked List Node Hopping: ~115.4 milliseconds (over 50x slower!)
Why? Pointer Chasing & Cache Thrashing:
Array:       [==== 64 Bytes (16 Ints) in L1 Cache ====] -> 1 Cache Miss per 16 elements
Linked List: Node 1 (0x10A0) [Miss] -> Node 2 (0x8F20) [Miss] -> Node 3 (0x44B0) [Miss]

In the linked list, each node is allocated independently on the heap at unpredictable addresses. Every pointer dereference (current = current->next) causes the CPU cache to miss, forcing the hardware to stall 200 cycles on every single node!


6. Memory Alignment & Struct Padding

Modern 64-bit CPUs read memory most efficiently when data is naturally aligned to address boundaries that are multiples of the data type size (e.g. 4-byte integers aligned to 4-byte addresses, 8-byte pointers aligned to 8-byte addresses).

Consider this C struct:

// Naive Struct Declaration (Total = 24 Bytes due to padding):
struct BadLayout {
    char a;      // 1 Byte payload (+ 7 Bytes padding)
    int64_t b;   // 8 Bytes payload
    char c;      // 1 Byte payload (+ 7 Bytes padding)
};

// Optimized Struct Declaration (Total = 16 Bytes):
struct GoodLayout {
    int64_t b;   // 8 Bytes payload
    char a;      // 1 Byte payload
    char c;      // 1 Byte payload (+ 6 Bytes trailing padding)
};

By reordering fields from largest to smallest, we eliminate internal padding and reduce memory consumption by 33%, fitting more structs per 64-byte cache line!


7. The Core Data Structure Taxonomy

                            DATA STRUCTURES TAXONOMY

            ┌──────────────────────────┴──────────────────────────┐
            ▼                                                     ▼
     LINEAR STRUCTURES                                  NON-LINEAR STRUCTURES
     (Sequential Memory)                                (Hierarchical / Graphs)
     ├── Contiguous Arrays                              ├── Binary Search Trees (BST)
     ├── Dynamic Vectors / Lists                        ├── Self-Balancing Trees (AVL / Red-Black)
     ├── Singly & Doubly Linked Lists                   ├── Binary Heaps & Priority Queues
     ├── Stacks (LIFO)                                  ├── Tries (Prefix Trees)
     ├── Queues & Deques (FIFO)                         ├── Graphs (Adjacency Lists & Matrices)
     └── Hash Tables (Buckets & Chaining)               └── Disjoint Set Union (DSU)

8. Key Takeaways & Conceptual Summary

💡 Hardware-Aware Engineering Principles
  • RAM is a linear byte array. Arrays compute index addresses instantly via O(1) arithmetic multiplication.
  • The CPU reads 64-byte cache lines. Contiguous memory structures maximize spatial locality.
  • Pointer chasing kills performance. Nodes scattered across heap memory cause continuous CPU cache misses.
  • Theoretical Big-O is not everything. Hardware cache effects often make contiguous O(n) arrays dramatically faster than pointer-based structures.
S

Computer Science educator, Software Engineer, Cloud Computing & Cloud Native Architect, and AI/ML Engineer. Founder & Owner of unus.one, softwork.ing, and codeworking.org.

Comments & Discussion