With search and iteration in place, the everyday ordered-set queries fall out cheaply. Today you round out the public API with membership, the smallest key, and the largest key - and close the chapter with a genuinely useful ordered collection.
Add Contains, Min, and Max, using level 0 for the minimum and the express lanes for the maximum.
The smallest key is trivial: it is head.forward[0], the very first node on the
bottom lane, since level 0 is sorted. The largest key is a nice mirror of search -
instead of stopping short of a target, you ride each express lane as far right as it
goes, dropping down when a lane ends, until you reach the final node on level 0. On a
tall list that finds the maximum in far fewer steps than walking every node.
Contains is just Search with the value thrown away, giving a clean boolean
membership test.
That completes the ordered-set surface: you can add and remove keys, test membership, find the extremes, iterate in order, query a range, and round up to a successor - all of it deterministic from a seed. What is still missing is the ability to ask about position: what is the rank of a key, or which key sits at index k? Answering those in better than linear time needs one more piece of bookkeeping on the forward pointers, and that is what the final chapter builds.
func (s *SkipList) Contains(key int) bool { _, ok := s.Search(key); return ok }func (s *SkipList) Min() (int, bool) {if n := s.head.forward[0]; n != nil { return n.key, true }return 0, false}// Max: ride each express lane to its end, then take the last level-0 node.