CS210 · Block 4 · Lesson 32

Recursion on a Linked List

Recursion over dynamic structures · the deferred operation on the stack · working tail to head · recursive free · the bridge to trees
At a glance: Recursion meets a real data structure. A linked list is recursive by definition, so most list operations transcribe straight into a base case (the empty list) plus one step of work on the rest. The idea worth the lesson is where that work lives: each suspended frame holds a deferred operation on the stack, and whether the work runs before or after the recursive call decides everything. The in-class trace widget makes that stack of deferred work visible; the lab has you write the toolkit and fix one recursive bug.
Contents
  1. Lesson Objectives
  2. Assigned Readings
  3. Pre-Class Work
  4. Lesson Materials and Overview
  5. In-Class Work
  6. After Class
1. Lesson Objectives

By the end of this lesson, cadets will be able to:

  1. Implement recursive functions that operate on linked data structures. (Outcomes 1, 2)
  2. Trace recursive operations on dynamic structures through the call stack. (Outcomes 1, 3)
  3. Manage memory correctly in recursive functions involving dynamic allocation. (Outcomes 2, 3)
2. Assigned Readings

The reading for this lesson is the instructor-written supplementary notes. There is no Beej chapter assigned; the notes are the source.

  • Lesson 32 Supplementary Notes: Recursion on a Linked List. Covers why a list is recursive by definition, the deferred operation each frame holds on the stack, the difference between doing work before versus after the recursive call, recursive freeing and the use-after-free order trap, the pitfalls specific to this lesson, and the bridge to trees. Read it before class.
3. Pre-Class Work
  • Read the supplementary notes
    Plan on about 30 minutes. Pay special attention to section 3 (the deferred operation on the stack) and section 4 (working tail to head). The in-class widget will make those two ideas concrete, so come having seen them once.
  • Recall your linked list and recursion work
    This lesson sits on top of the linked lists you built in the last three lessons and the recursion you met at Lesson 11. If the node-and-pointer picture or the base-case / recursive-case split feels rusty, review before class. Schedule EI if it does not come back quickly.
4. Lesson Materials and Overview

Recursion on a linked list is mostly transcription: the structure is recursive, so the function is too. The reference material below previews the concepts; the in-class trace widget shows them in motion, and the lab is where you write them.

Jump to
Slides A list is recursive The deferred operation Working tail to head Freeing a list DFCS standard

Slides

The Lesson 32 deck walks through the recursive structure of a list, the deferred operation each frame holds, the before-versus-after-the-call distinction, recursive freeing and the order trap, and the bridge to trees. Roughly 30 to 40 minutes of lecture, then into the trace widget and the lab.

Lesson 32 slide deck (PDF) — opens in a new tab

A list is recursive by definition

A linked list is either empty (a NULL pointer) or one node followed by another linked list, the part next points at. That second half is itself a list, so the structure is defined in terms of a smaller version of itself. The base case is the empty list; the thing that shrinks is the list, because each call passes node->next; and it terminates because a finite list ends at NULL.

The deferred operation on the stack

When a function reaches return 1 + list_length(node->next); it cannot finish until the recursive call returns, so it suspends and the 1 + it still owes is saved in its stack frame. Go several nodes deep and several frames stack up, each holding its own deferred operation, waiting. The answer is assembled on the way back up as the calls return, not on the way down. The trace widget draws this directly, showing each suspended frame holding 1 + ? and then resolving it.

Working tail to head

For length and sum you would normally use a loop, and Lesson 33 takes up that tradeoff. The place recursion clearly wins on a singly linked list is any operation that must run from the tail back toward the head, because the list has no backward pointer. Putting the work after the recursive call gives you tail-first order for free: the deepest frame acts first. That is the shape of reverse printing and of the collect_reverse function in the lab.

Freeing a list, and the order trap

Recursive freeing also acts after the call: free the rest of the list first, then this node's word string, then the node itself. The order is not optional. Freeing the node first and then reaching for node->next reads memory you just returned, which is a use after free. Each node owns two heap allocations, the node and its word, and both must be freed.

DFCS C Programming Standard

This lesson revisits two standing rules rather than introducing a new section. Section 8.5 (always free dynamically allocated memory) returns with a twist: when a struct member is itself a heap pointer, freeing the struct means freeing that member first, so free_list must free each node's word before the node. Section 2.4 (inline comments) earns its keep in recursive code: a one-line comment naming the base case and what shrinks makes a recursive function far easier for the next reader. See the standard in the course Resources for the full text.

5. In-Class Work

Two things to do in class. Use the checklist to track your progress.

  • Work through the recursion list trace below. Five recursive functions traced over a linked list of structs, each ending in a prediction. Watch the deferred operation stack up and resolve. About 20 minutes.
  • Complete the Lesson 32 lab: recursion on a linked list. Implement five recursive functions and fix one recursive bug. Auto-graded through GitHub Classroom; accept the assignment here. Full instructions in the lab repo README.

Recursion List Trace

Five functions: list_length, list_sum, find, print_reverse, and free_list. Step through each one and watch two things: the call stack growing on the left with each frame holding its deferred work, and the heap below with the node the active frame points at lit up. Answer the prediction at the end of each trace to mark it complete.

Before you start

Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Blackboard reflection quiz.

Recursion on a linked list

Step through five recursive functions over a linked list of structs. The call stack grows on the left; each suspended frame shows the deferred work it is holding (for example 1 + ?). The heap is below, and the node the active frame points at lights up. At the end of each trace, answer one prediction to mark it complete.

Call stack (most recent on top)
Heap — the linked list of node_t nodes
Each node is a node_t struct: its num and word fields sit in the DATA cell, and next holds the address of the following node (or NULL). The lit node is the one the active frame points at.
Press Step to begin.
How to read it: the highlighted line in the code pane is what is about to run. Each call pushes a frame onto the stack; the arrow from a frame points to the node that frame is working on. A frame turns green and shows its return value as it returns, then pops. In print_reverse and free_list, watch how the work happens after the recursive call, on the way back up the stack. Miss a prediction twice and the hint button pulses. Stuck on the concept? Schedule EI.
6. After Class
  • Finish the lab if you did not complete it in class. Submit through GitHub Classroom before the next lesson. Run valgrind --leak-check=full on your demo before you submit; the autograder will.
  • Complete the Lesson 32 reflection in Blackboard: enter the widget completion code and answer the reflection prompt. Attach your screenshot of the completion screen.
  • Read the Lesson 33 supplementary notes (recursion versus iteration, and the tradeoffs) for next time. Lesson 33 answers the question this lesson raised: when should you actually reach for recursion?
  • Heads up: Quiz 10 at Lesson 34 covers Recursion II and III together.
Need help? Schedule EI with your instructor. Bring specific code, the exact error or valgrind output, and the input you ran. If a push or pull is giving you trouble, see the Git troubleshooting reference card in the course Resources.