Solution

ID: past-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford/2022/functional-programming-design-and-analysis-of-algorithms-resit/2/h/solution

Skip whole trees using their cached sizes, then descend through one tree:
index :: List a -> Int -> a
index (List ts) i
  | i < 0     = error "index: negative index"
  | otherwise = seek ts i
  where
    seek [] _ = error "index: out of bounds"
    seek ((w,t):us) j
      | j < w     = at w t j
      | otherwise = seek us (j-w)
    at _ (Leaf x) 0 = x
    at w (Node x l r) j
      | j == 0 = x
      | j <= h = at h l (j-1)
      | otherwise = at h r (j-1-h)
      where h = w `div` 2
    at _ _ _ = error "index: invalid representation"
After skipping a size- tree, the desired index decreases by . Inside a node, position zero is the root, positions belong to the left child and the following positions to the right child. This proves correctness by structural induction on the search.
There are at most forest entries by the supplied bound, and each tree has logarithmic height. Consequently a valid query takes time, with logarithmic worst cases. On a conventional linked list, xs !! i follows links and costs , hence in the worst case. The first element remains a constant time query in either representation.

New to topics? Read the docs here!