← Back to list

Day 9 — Choosing the Right Data Structure Is More Important Than I Thought

When I first started programming, arrays seemed to be the answer for almost everything.

Sebastiao Cosme Agostinho · 2026-07-01 01:40 · 0 claps · 3.0 min read
#software-engineering #programming #technology #data-structures #linked-lists
Open on Medium ↗
Wiki topics: 💻 · Programming

Day 9 — Choosing the Right Data Structure Is More Important Than I Thought

When I first started programming, arrays seemed to be the answer for almost everything.

Need to store data?

Use an array.

Need to search?

Loop through it.

Need to add an element?

Use push().

It worked, so I never questioned it.

Today’s lesson changed that perspective.

I realized that software engineering isn’t just about solving problems.

It’s about choosing the right solution for the problem at hand.

Arrays vs. Linked Lists

At first glance, Arrays and Linked Lists look very similar.

Both store collections of elements.

The difference lies in how they organize data.

With an array, every element has an index.

Typescript:

const numbers = [10, 20, 30, 40];

console.log(numbers[2]); // 30

Because arrays store their elements sequentially in memory, accessing an element by index is extremely fast.

Time Complexity: O(1).

A Linked List works differently.

Each node only knows about the next node.

Typescript:

class Node<T> {
    constructor(
        readonly value: T,
        public next: Node<T> | null = null
    ) {}
}

If we want to reach the third element, we can’t jump directly to it.

We have to visit every node until we get there.

Head
 ↓
[10] → [20] → [30] → [40]

This makes searching by position slower (O(n)).

However, inserting a new node at the beginning becomes incredibly efficient.

Typescript:

const newNode = new Node(5);

newNode.next = head;
head = newNode;

No elements need to be shifted.

Only one pointer changes.

Time Complexity: O(1).

That led me to one important conclusion:

There isn’t a “better” data structure.

There is only the one that best fits the problem you’re solving.

Encapsulation Still Matters

One detail I appreciated was that even a simple node shouldn’t expose unnecessary state.

Instead of this:

Typescript:

class Node {
    value: number;
    next: Node | null;
}

A better design is:

Typescript:

class Node<T> {
    readonly value: T;

    next: Node<T> | null = null;

    constructor(value: T) {
        this.value = value;
    }
}

The value never changes after creation.

Only the Linked List controls how nodes are connected.

Even when studying data structures, software engineering principles still apply.

Understanding Recursion

Recursion used to feel mysterious to me.

A function calling itself sounded complicated.

Today’s lesson simplified that idea.

Every recursive solution follows two simple rules:

  1. There must always be a base case.
  2. Every recursive call must move closer to that base case.

For example:

Typescript:

function countdown(number: number): void {
    if (number === 0) {
        return;
    }

    console.log(number);

    countdown(number - 1);
}

Execution looks like this:

countdown(5)
 ↓
countdown(4)
 ↓
countdown(3)
 ↓
countdown(2)
 ↓
countdown(1)
 ↓
countdown(0)
 ↓
stop

Without the base case…

Typescript:

function countdown(number: number): void {
    countdown(number - 1);
}

…the function never stops.

Eventually the application crashes with a Stack Overflow.

Optimization Isn’t Always About Smarter Code

The Fibonacci example was probably my favorite part of the lesson.

A naïve recursive solution looks simple.

Typescritp:

function fibonacci(n: number): number {

    if (n <= 1) {
        return n;
    }

    return fibonacci(n - 1) + fibonacci(n - 2);
}

The problem?

It keeps solving the same subproblems over and over again.

Instead, we can cache previous results.

Typescript:

function fibonacci(
    n: number,
    memo = new Map<number, number>()
): number {

    if (n <= 1) {
        return n;
    }

    if (memo.has(n)) {
        return memo.get(n)!;
    }

    const value =
        fibonacci(n - 1, memo) +
        fibonacci(n - 2, memo);

    memo.set(n, value);

    return value;
}

This technique is called memoization.

The algorithm becomes dramatically more efficient because it avoids repeating work.

One small idea changes the complexity from O(2ⁿ) to O(n).

That really made me think.

Sometimes performance isn’t about writing more clever code.

It’s simply about avoiding unnecessary work.

Divide and Conquer

Another interesting example was recursive binary search.

Instead of checking every element one by one:

1 3 5 7 9 11 13 15

We repeatedly discard half of the search space.

1 3 5 7 | 9 11 13 15
        ↑

Target > 9?

Discard the left half.
Target > 9?

Discard the left half.

Each comparison cuts the remaining work in half.

That's why binary search runs in O(log n), making it one of the most efficient searching algorithms for sorted collections.

My Biggest Takeaway

Before this lesson, I thought data structures were mostly about implementation.

Now I’m beginning to see them as design decisions.

Arrays.

Linked Lists.

Iteration.

Recursion.

Memoization.

None of these concepts exist in isolation.

Each one represents a different trade-off between simplicity, memory usage, and performance.

The more I study software engineering, the more I realize that becoming a better developer isn’t about memorizing algorithms.

It’s about understanding why one solution is more appropriate than another.

I’m documenting this journey publicly to reinforce what I’m learning and to track my progress one lesson at a time.


메타데이터
post_id
4d425ba451d9
slug
day-9-choosing-the-right-data-structure-is-more-important-than-i-thought-4d425ba451d9
url
https://medium.com/@scosmexs/day-9-choosing-the-right-data-structure-is-more-important-than-i-thought-4d425ba451d9
canonical_url
https://medium.com/@scosmexs/day-9-choosing-the-right-data-structure-is-more-important-than-i-thought-4d425ba451d9
author_url
https://medium.com/@scosmexs
status
ok
fetched_at
2026-07-09 09:29:37