Skip to content
Part IA Michaelmas Term

Tree Traversals

Three depth-first orders

Tree traversal means visiting every node in a systematic order. Knuth identifies three depth-first traversals, all of which process the left subtree before the right subtree. They differ only in when the node’s label is visited:

TraversalOrderMnemonicApplication
PreorderNode, Left, RightNLRPolish notation
InorderLeft, Node, RightLNRSorted output for BSTs
PostorderLeft, Right, NodeLRNReverse Polish notation

Tree traversals

Naive implementations

Each traversal converts a tree into a list of labels:

let rec preorder = function
  | Lf -> []
  | Br (v, t1, t2) ->
      [v] @ preorder t1 @ preorder t2

let rec inorder = function
  | Lf -> []
  | Br (v, t1, t2) ->
      inorder t1 @ [v] @ inorder t2

let rec postorder = function
  | Lf -> []
  | Br (v, t1, t2) ->
      postorder t1 @ postorder t2 @ [v]

Example: given a tree with root A, left child B (children D, E), right child C (children F, G):

TraversalResult
PreorderABDECFG
InorderDBEAFCG
PostorderDEBFGCA

Inorder on BSTs

Applying inorder to a binary search tree yields the keys in sorted order. This property is the basis of treesort: build a BST from the input, then traverse inorder to get the sorted list.

Inefficiency

All three naive traversals suffer from the same problem: repeated uses of @ (append). In the worst case (a degenerate tree), the time complexity is O(_n_²) because each @ copies its first argument. The next note shows how to fix this with accumulating parameters.