CMD Guide
HomeDSALinked List

Operations on Doubly Linked List

A doubly linked list stores, in every node, a value plus two pointers — next and prev — so any node can reach both its neighbors in O(1) without re-walking the list; this second pointer is the entire reason DLL operations differ from singly linked list operations: every insert/delete must keep both links consistent on both sides of the edit, in exchange for being able to delete a given node, walk backward, or search from whichever end is closer.

Recognize the pattern

Brute force vs optimal

Brute force (as if singly linked): to delete node target, walk from head to find its predecessor — O(n) time, O(1) space, even though you already hold a reference to target.

Optimal (using prev): read target.prev directly — O(1) time, O(1) space. The DLL trades one extra reference per node (4 bytes with HotSpot compressed oops, 8 without — subject to 8-byte alignment rounding) for turning an O(n) predecessor lookup into an O(1) pointer read.

Complexity from first principles

Worked example: delete node with value 30

List: 10 <-> 20 <-> 30 <-> 40, and we already hold a reference target to the node holding 30.

StepActionState after
1p = target.prev (node 20), q = target.next (node 40)p=20, q=40
2p.next = q — write #120.next → 40
3if q != null: q.prev = p — write #240.prev → 20
4atarget.next = null — write #3 (help GC)30.next cleared
4btarget.prev = null — write #4 (help GC)30.prev cleared

Result: 10 <-> 20 <-> 40. Zero traversal — 4 pointer writes total (2 to bridge the neighbors, 2 to isolate the removed node), because we started from the node itself instead of scanning for it.

Java implementation

class DNode {
    int val;
    DNode prev, next;
    DNode(int val) { this.val = val; }
}

class DoublyLinkedList {
    DNode head, tail;

    // O(1): 2 reassignments (head, and head.prev if list was non-empty)
    void insertAtHead(int val) {
        DNode n = new DNode(val);
        n.next = head;
        if (head != null) head.prev = n;
        head = n;
        if (tail == null) tail = n;
    }

    // O(1): mirror of insertAtHead, using tail instead
    void insertAtTail(int val) {
        DNode n = new DNode(val);
        n.prev = tail;
        if (tail != null) tail.next = n;
        tail = n;
        if (head == null) head = n;
    }

    // O(1): caller already holds the node reference
    void deleteNode(DNode target) {
        if (target.prev != null) target.prev.next = target.next;
        else head = target.next;
        if (target.next != null) target.next.prev = target.prev;
        else tail = target.prev;
        target.next = null;
        target.prev = null;
    }

    // O(1): delegates to deleteNode once the reference is known
    void deleteAtHead() {
        if (head != null) deleteNode(head);
    }

    void deleteAtTail() {
        if (tail != null) deleteNode(tail);
    }

    // O(1) once you hold anchor: rewires 4 pointers, no traversal
    void insertBefore(DNode anchor, int val) {
        DNode n = new DNode(val);
        DNode p = anchor.prev;
        n.prev = p;
        n.next = anchor;
        anchor.prev = n;
        if (p != null) p.next = n; else head = n;
    }

    void printForward() {
        for (DNode c = head; c != null; c = c.next) System.out.print(c.val + " ");
    }
}

All of these reuse the same two moves as the worked example above: snapshot the neighbors, then rewrite pointers on both sides — insertAtTail, deleteAtHead/deleteAtTail, and insertBefore (the mirror insertAfter just swaps prev/next roles) are all O(1) once the anchor node is known, confirming the head/tail row of the complexity table without needing separate proofs.

Pitfalls

When to use / when not — DLL vs singly linked list vs array

NeedBest fitWhy
O(1) delete given a node ref (LRU, undo/redo)Doubly linked listprev pointer avoids O(n) predecessor scan
Minimize memory, only forward traversalSingly linked listsaves one pointer per node; DLL's prev field is dead weight
Random access by index, cache localityArray / ArrayListO(1) index access, contiguous memory; DLL is O(min(k,n-k)) to index and pointer-chases (cache-unfriendly)

Don't reach for a DLL just for backward traversal if you never delete/insert mid-list from a held reference — the extra pointer and bookkeeping isn't worth it. A neat payoff when you do have both ends: palindrome check is Θ(n) time / Θ(1) space with two pointers meeting from head and tail, while a singly list must reverse half the list or stack values (often Θ(n) extra space) to compare.

Takeaways

Recall: Why can a doubly linked list delete a given node in O(1) while a singly linked list generally cannot, and why does index-based access improve from O(k) to O(min(k, n−k))?


Compiled from standard DSA references (GeeksforGeeks, CLRS-style linked list treatments) and verified against hand-traced pointer manipulation.

🤖 Don't fully get this? Learn it with Claude

Stuck on Operations on Doubly Linked List? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Operations on Doubly Linked List** (DSA) and want to truly understand it. Explain Operations on Doubly Linked List from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Operations on Doubly Linked List** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Operations on Doubly Linked List** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Operations on Doubly Linked List** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes