Unit 1 · Lesson 420 minAcademic review pending

A list you can walk backwards

Adding a prev pointer alongside next lets you delete a node given only a pointer to it — something a singly linked list cannot do without walking from the head.

Choose explanation

After this lesson

You should be able to

  • Declare a doubly linked node with prev and next pointers.
  • Insert and delete while correctly updating both directions.
  • Explain the memory and complexity trade-off against a singly linked list.

Try it before you read

Try it live

dlist.c0 node(s)

head → NULL

Every node also points back — that backward arrow is what a plain singly linked list does not have.

01

Two pointers instead of one

A doubly linked node adds a prev pointer next to next. Now you can walk the list in either direction, and — this is the important part — given a pointer to any node, you already have a pointer to its predecessor without searching for it.

That is a real trade, not a free upgrade: every node now costs one more pointer's worth of memory, and every insertion or deletion must correctly update two links instead of one.

One more pointer, one new capability
struct DNode {
    int data;
    struct DNode *prev;
    struct DNode *next;
};

typedef struct DNode DNode;
02

Deleting a known node

In a singly linked list, deleting a node you have a pointer to still requires walking from head to find its predecessor, because only the predecessor's next can be rewired to skip it. In a doubly linked list, the node itself already knows its predecessor.

Four pointer updates handle it: the predecessor's next skips forward, the successor's prev skips backward, then the node is freed. Get the order wrong and you free a node before reading the pointers you needed from it.

No head, no search — just the node itself
void delete_node(DNode *node)
{
    if (node->prev != NULL)
        node->prev->next = node->next;
    if (node->next != NULL)
        node->next->prev = node->prev;

    free(node);   /* read prev and next first, free last */
}
03

Inserting after a given node

Insertion is the mirror image: build the new node's own links first, pointing correctly at its neighbours, then rewire the two neighbours to point at it. Building the new node's links before touching the neighbours avoids losing a reference partway through.

This ordering discipline — build the new piece fully before wiring it in — is the same idea as the front-insertion order from Lesson 2, now with twice as many pointers to get right.

Try it yourself

Build a doubly linked list of five values by appending each at the end, then print it forwards and then backwards using the same list.

Need a hint?

Printing backwards means walking from the last node using prev — you need a way to reach the last node first.

Check the worked solution

Backwards printing is only possible at all because of the prev pointer added in this lesson — a singly linked list has no way to do this without extra storage such as a stack. Finding the tail once by walking forward and reusing it for both the append and the backward print avoids re-walking the list from head each time.

#include <stdio.h>
#include <stdlib.h>

struct DNode { int data; struct DNode *prev; struct DNode *next; };
typedef struct DNode DNode;

DNode *append(DNode *head, int value)
{
    DNode *node = malloc(sizeof(DNode));
    node->data = value;
    node->next = NULL;

    if (head == NULL) {
        node->prev = NULL;
        return node;
    }

    DNode *tail = head;
    while (tail->next != NULL) tail = tail->next;
    tail->next = node;
    node->prev = tail;
    return head;
}

int main(void)
{
    DNode *head = NULL;
    int values[5] = {10, 20, 30, 40, 50};

    for (int i = 0; i < 5; i++)
        head = append(head, values[i]);

    printf("Forward:  ");
    for (DNode *cur = head; cur != NULL; cur = cur->next)
        printf("%d ", cur->data);

    DNode *tail = head;
    while (tail->next != NULL) tail = tail->next;

    printf("\nBackward: ");
    for (DNode *cur = tail; cur != NULL; cur = cur->prev)
        printf("%d ", cur->data);
    printf("\n");

    return 0;
}

Quick check

Given only a pointer to a node in the middle of a list, why is deletion easier in a doubly linked list than a singly linked one?

Select an answer to check your thinking.

Why this lesson exists

Syllabus mapping

Doubly Linked List

Maps to course outcomes CO1, CO4.