DSA with Irma: Linked Lists

DSA with Irma: Linked Lists

Welcome back to Firmacodes! If you’re new here, I’m Irma, a CS student at NYU Abu Dhabi, and this is my little corner of the internet where I turn projects, concepts and late-night study sessions into content that actually makes sense. This post is part of the DSA with Irma series, where we go topic by topic through the core DS concepts you’ll need as a developer. Today we’re diving into Linked Lists, all three kinds.

Let’s get into it!

Introduction

If arrays are the tidy, organized friend who keeps everything in a numbered shelf, linked lists are the chaotic creative who chains sticky notes together across a room. Harder to jump to a random note, but way easier to add or remove one without rearranging everything.

In this lecture we’re going through all three types: Singly, Doubly, and Circular linked lists. By the end you’ll understand how they’re structured, how the key operations work, and why the small differences between them matter more than you’d think.

The Basics: What Even Is a Linked List?

DSA with Irma: Linked Lists

A linked list is a collection of nodes. Each node holds two things:

  • the data (the actual value you’re storing)
  • a pointer (or two) to the next node in the chain

Unlike arrays, the nodes don’t sit next to each other in memory, they’re scattered around, connected only by those pointers. This makes insertion and deletion fast (no shifting), but random access slow (no indices).

Part 1: Singly Linked List

DSA with Irma: Linked Lists

The simplest form. Each node has one pointer: next, pointing to the node after it. The last node’s next is nullptr.

This is how the Node Class could look:

struct Node {
    int elem;
    Node* next;
};
Key operations

a) Traversal is the foundation of everything in a singly LL. You walk the list by moving a pointer forward:

Node* x = head;
while (x != nullptr) {
    // do something with x->elem
    x = x->next;
}

b) Adding to the front – create a new node, point its next to the current head, then update head:

void addFront(int elem) {
    Node* x = new Node;
    x->elem = elem;
    x->next = head;
    head = x;
}

c) Removing from the front – save a pointer to the current head, move head forward, then delete the old one:

void removeFront() {
    Node* old = head;
    head = head->next;
    delete old;
}

Simple, right? Now let’s add a second pointer and things get interesting.

Part 2: Doubly Linked List

DSA with Irma: Linked Lists

Each node now carries three things: data, a next pointer, and a prev pointer. This lets you traverse in both directions – front to back and back to front.

One common implementation also adds two dummy nodes: a header (before the first real node) and a trailer (after the last). They store no data and exist purely as sentinel anchors so you never have to check for null at the boundaries.

A possible implementation of the Node class:

struct DNode {
    int elem;
    DNode* next;
    DNode* prev;
};

Important part: Constructor!

Set up the two dummy nodes and wire them together.

DLinkedList() {
    header = new DNode;
    trailer = new DNode;
    header->next = trailer;
    trailer->prev = header;
}

Key detail: the header and trailer just store pointers. header->next points forward, trailer->prev points back. Their own prev and next on the outer edges are left as nullptr.

Important part: Destructor!

When the list is destroyed, clean up every node, then the dummies:

~DLinkedList() {
    while (!empty()) removeFront();
    delete header;
    delete trailer;
}

Check out all other method implementations on my GitHub.

Part 3: Circularly Linked List

DSA with Irma: Linked Lists

Similar to a singly linked list (one pointer per node) but with one key twist: the last node’s next points back to the head instead of nullptr. The list loops.

There’s no nullptr anywhere in a non-empty circular list. This changes how you write your loops, you can’t use (x != nullptr) as your condition anymore.

  • When the list is empty, the new node becomes both head AND tail, so it must point to itself.

Check out all other method implementations on my GitHub.

Side by side comparison

DSA with Irma: Linked Lists

Key takeaways

  • Singly LL – simplest, one direction, watch for nullptr
  • Doubly LL – the general add(v, elem) and remove(v) pattern makes all other operations just one-liners; dummy header/trailer eliminate edge cases
  • Circular LL – no nullptr anywhere; always use head as your loop termination condition; the empty-list case for addFront is a common gotcha

Next lecture: Stacks and Queues.

Resources

If you are enjoying DSA with Irma and want to keep learning alongside me, here is where you can find more:

  • 🖥️ GitHub: Browse my projects, code snippets, and experiments.
  • 📸 Instagram: Coding tips, behind-the-scenes, and my developer journey.
  • 😆 LinkedIn: Tech updates, networking, and professional milestones.
  • 👩🏻‍💻 Portfolio: Explore all my work in one place.

I would love to hear what you think about learning JavaScript this way, drop me a message anytime!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top