CASE STUDY 01 · DATA STRUCTURES

Intermediate Doubly linked list

Browser History & Navigation

Implement Visit, Back and Forward while preserving link symmetry, current-page state and correct deletion of abandoned forward history.

01 · PROBLEM DEFINITION

History is a movable timeline

A browser must remember visited pages and maintain a cursor called the current page. Back moves the cursor toward older pages; Forward moves toward newer pages. Visiting a new page after going Back creates a new timeline and permanently discards the old forward branch.

Important distinction: Back does not delete a page. It only moves current. Deletion occurs when a new page is visited from the middle of history.

State

Ordered pages plus one current position.

Navigation

Move one link without reallocating data.

Branch change

Free all nodes after current before appending.

02 · REQUIREMENTS

Expected behaviour and boundaries

OperationPreconditionPostcondition
VisitNon-empty title and URLNew page becomes current and last
Backcurrent.previous existscurrent moves exactly one node left
Forwardcurrent.next existscurrent moves exactly one node right
Show currentNoneState remains unchanged
ClearNoneAll nodes freed; first/current become NULL

Edge cases

  • Back or Forward on an empty history
  • Back at the first page and Forward at the last page
  • Visiting the first page when both pointers are NULL
  • Visiting from the middle of a multi-node history
  • Clearing once and clearing an already empty history
03 · STRUCTURE SELECTION

Why a doubly linked list?

Page = { title, url, *previous, *next }
History state = { *first, *current }
NULL
A
first
B
current
C
NULL

A singly linked list supports Forward but cannot move Back in O(1). Two stacks are another strong solution: Back stack + current + Forward stack. The doubly linked list is chosen here because it exposes the complete timeline and makes bidirectional relationships visible.

CandidateBackForwardDisplay timelineDecision
Array + indexO(1)O(1)O(n)Simple, but fixed/resized capacity
Two stacksO(1)O(1)Less directExcellent production model
Doubly linked listO(1)O(1)O(n)Chosen for pointer learning
04 · CORRECTNESS INVARIANTS

What must always remain true?

  1. If first != NULL, then first->previous == NULL.
  2. For every adjacent pair A and B: A->next == B and B->previous == A.
  3. current is NULL only when history is empty; otherwise it points to a reachable node.
  4. The final node’s next is NULL.
  5. After Visit, current->next == NULL because the new page is last.
Common bug: Freeing forward nodes but forgetting current->next = NULL leaves a dangling pointer. A later Forward dereferences released memory.
05 · ALGORITHMS

Operations as pointer transformations

Visit from the middle

A
B
current
C
D
  1. Walk from current->next, save each next pointer, then free the current forward node.
  2. Set current->next = NULL.
  3. Allocate the new page N.
  4. Set N->previous = current and current->next = N.
  5. Move current = N.
A
B
N
current
NULL

Clear safely

Never read node->next after free(node). Store it first, free the node, then advance to the saved address.

06 · COMPLETE IMPLEMENTATION

Compiler-ready C11 program

programs/browser-history.c
Open Compiler
Loading source…

Reading order

Movement

Read moveBack and moveForward first; they only change current.

Mutation

Then read visit and deleteForwardHistory.

Cleanup

Finally verify every allocation reaches clearHistory.

07 · INTERACTIVE TRACING

Trace the branch-deletion rule

  1. Visit page A.
  2. Visit page B.
  3. Visit page C.
  4. Press Back.
  5. Visit new page D from B.
  6. Delete abandoned C branch.
  7. Connect new page D.
  8. Try Forward.
Current state

Press Next to begin.

08 · TEST DESIGN

Test navigation and memory edges

Test 1 — Linear navigation
Visit A, B, C; Back twice; Forward once. Current must be B and complete history remains A-B-C.
Test 2 — New branch
Visit A-B-C, Back to B, Visit D. History must become A-B-D; Forward must report unavailable.
Test 3 — Boundary movement
At A, Back must not move. At final page, Forward must not move.
Test 4 — Clear and reuse
Clear a multi-node history, then Visit X. X must become both first and current without touching freed memory.
Test 5 — Empty inputs
An empty title or URL must not allocate or modify history.
09 · COMPLEXITY

Time and space costs

OperationTimeExtra spaceReason
Back / Forward / CurrentO(1)O(1)One pointer access
Visit at endO(1)O(1)No forward branch
Visit from middleO(k)O(1)Free k forward nodes
Show / Clear historyO(n)O(1)Traverse every node

Total storage is O(n) for n retained pages.

10 · PRACTICE

Check and extend your understanding

What changes when Back succeeds?

Which condition must hold immediately after Visit?

Extension challenges

  1. Add timestamps and display most-recent visit time.
  2. Limit history to 10 pages and delete the oldest automatically.
  3. Implement the same behaviour using two stacks and compare code.
  4. Add tab objects, each with an independent history.
11 · INTERVIEW PREPARATION

Defend your structure choice

Why are both previous and next required?

They provide O(1) movement in either direction. A singly linked list would need a scan from first to locate the predecessor.

When are two stacks preferable?

When only Back/Forward operations matter and displaying the entire ordered timeline is unnecessary. A new Visit simply clears the Forward stack.

What is a dangling pointer in this project?

A link that still holds the address of a freed Page. Setting current->next to NULL after branch deletion removes that dangerous reference.

How would you detect memory errors?

Test repeated branch changes and clears, then run with AddressSanitizer or Valgrind to detect leaks and invalid accesses.

12 · KEY TAKEAWAY

A data structure is state plus invariants

The list alone is not browser history. Correct behaviour comes from interpreting current as a cursor, distinguishing movement from mutation and restoring every link invariant after deletion or insertion.