Code

bst.go — the skeleton

Create bst.go. As since lesson 7 — package, types, signatures and contracts in the comments; the bodies are yours.

Worth noting:

  • Put with a key already present REPLACES the record. Exactly as in lesson 10: the two structures make the same promise about keys, and differ in what else they promise.
  • A new node always becomes a leaf. Do not rearrange anything. That is not a simplification or a placeholder — the shape that insertion order produces is what step 7 is about. "Fix" it and there is nothing left to measure.
  • Every key comparison goes through c.Hit(). That count is the depth you walked.
  • Range must skip subtrees that cannot contain an answer. The test checks that far fewer nodes were visited than exist — a full walk with a filter at the end does not count.
  • Height counts nodes, not edges. An empty tree is 0, a single node is 1. Step 7's table depends on that definition.

Recursion is natural here: Keys, Range and Height describe themselves in terms of themselves, like lesson 5's traversals. Get, Put, Min and Max are plain loops — recursion buys them nothing.

Gotcha

Put has to modify the pointer inside the node, not a copy of it.

cur := t.root          // a copy: attach a node to cur and the tree never sees it
cur := &t.root         // a pointer to the pointer: `*cur = &node{...}` changes the tree

This is the classic mistake in this exercise, and it does not announce itself: Put returns no error, Len goes up, and Get finds nothing. The second form — or a recursive insert that returns the new subtree — are both correct.