algorithm
exercise
introduction
problem-solving
computer science

Introduction to Algorithm, Exercise 10.2-4

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Exercise 10.2-4 in CLRS focuses on a subtle optimization for linked-list search loops. The baseline search checks two conditions each iteration: whether the pointer reached the sentinel and whether the current key matches the target. The exercise asks how to eliminate the sentinel-boundary check from the loop body.

In a doubly linked list with sentinel node L.nil, a typical search looks like this:

text
1x = L.nil.next
2while x != L.nil and x.key != k
3    x = x.next
4return x

Each iteration evaluates two predicates:

  • x != L.nil
  • x.key != k

The second predicate is the real search condition. The first exists only to avoid reading key from the sentinel. Exercise 10.2-4 removes that boundary check from the loop using a sentinel-key trick.

Sentinel-Key Technique

The idea is simple:

  1. put target key k into the sentinel key field temporarily,
  2. loop only on key mismatch,
  3. stop naturally when key equals k.

Pseudocode shape:

text
1x = L.nil.next
2L.nil.key = k
3while x.key != k
4    x = x.next
5return x

Why this works:

  • if real key exists in data nodes, loop stops there,
  • if key does not exist, traversal reaches sentinel,
  • sentinel key equals k, so loop stops safely.

You then determine success by checking whether returned node is sentinel.

Full Implementation in Python

The code below models a doubly linked list with a sentinel and shows both baseline and optimized search.

python
1from dataclasses import dataclass
2from typing import Optional
3
4
5@dataclass
6class Node:
7    key: Optional[int] = None
8    prev: "Node | None" = None
9    next: "Node | None" = None
10
11
12class DoublyLinkedList:
13    def __init__(self):
14        self.nil = Node()
15        self.nil.prev = self.nil
16        self.nil.next = self.nil
17
18    def insert_front(self, key: int) -> None:
19        x = Node(key=key)
20        x.next = self.nil.next
21        x.prev = self.nil
22        self.nil.next.prev = x
23        self.nil.next = x
24
25    def search_baseline(self, key: int) -> Optional[Node]:
26        x = self.nil.next
27        while x is not self.nil and x.key != key:
28            x = x.next
29        return None if x is self.nil else x
30
31    def search_sentinel_key(self, key: int) -> Optional[Node]:
32        x = self.nil.next
33        old_sentinel_key = self.nil.key
34        self.nil.key = key
35        while x.key != key:
36            x = x.next
37        self.nil.key = old_sentinel_key
38        return None if x is self.nil else x
39
40
41if __name__ == "__main__":
42    ll = DoublyLinkedList()
43    for value in [8, 4, 12, 7]:
44        ll.insert_front(value)
45
46    print(ll.search_baseline(12).key)      # 12
47    print(ll.search_sentinel_key(99))      # None

This implementation restores original sentinel key after search, which makes the method safer if sentinel metadata matters elsewhere.

Correctness Argument

The optimization preserves correctness because the search invariant remains the same: x always references a node in list order from head toward sentinel.

Termination cases:

  • target is in list: loop stops at first matching node,
  • target missing: loop eventually reaches sentinel, whose temporary key equals target, so loop stops.

Returned value handling:

  • return None if result node is sentinel,
  • otherwise return matching data node.

No false positives occur because sentinel is explicitly filtered after loop.

Complexity Impact

Asymptotic complexity remains O(n) for list of n data nodes. The optimization reduces constant factor in the hot loop by replacing two checks with one.

Why this mattered historically:

  • branch-heavy loops were expensive on older hardware,
  • fewer conditions often improved throughput in tight scans.

In modern code, clarity can be more important than micro-optimizations, but sentinel patterns still appear in low-level data structures and language runtimes.

When to Use This Pattern

Use the sentinel-key pattern when:

  • list already has a sentinel design,
  • search loop is performance-critical,
  • temporary sentinel key mutation is safe in your concurrency model.

Avoid it when:

  • codebase prioritizes readability over tiny loop savings,
  • sentinel key cannot be temporarily overwritten,
  • shared concurrent reads can observe transient sentinel values.

If thread safety matters, protect mutation with synchronization or prefer non-mutating search.

Common Pitfalls

A common bug is forgetting to restore sentinel key after search. That can break unrelated logic that assumes sentinel key is constant.

Another mistake is returning sentinel as if it were a valid node when the key is absent. Always convert sentinel result to None or explicit not-found marker.

Developers also apply this trick to lists without a sentinel node. In that case the method does not work because there is no guaranteed terminal node to hold the target key.

Finally, avoid mixing this optimization with external iteration that assumes sentinel key is never touched.

Summary

  • Exercise 10.2-4 removes per-iteration sentinel boundary checks in list search.
  • Technique: temporarily assign target key to sentinel, then loop only on key mismatch.
  • Correctness is preserved by checking whether the returned node is sentinel.
  • Runtime stays O(n), with a smaller loop constant factor.
  • Restore sentinel state and handle concurrency concerns when using this optimization.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.