10.6 Traversing a Tree 241
then applies that operator to the top two arguments on the stack. With algebraic
expressions, it is easy to think inside out, in a postorder fashion. With LISP or
Scheme, the intent is that one thinks top-down, with a preorder mindset.
10.6.1 Breadth-First and Depth-First Traversal
There are two other traversal methods for trees (or more generally for graphs). A
depth-first traversal is essentially the same as an inorder traversal. The order in
which nodes are visited is the same (left subtree, root, right subtree), but a depth-
first traversal is used in many instances as part of a depth-first search, which will
be discussed in the next chapter. There are two variations of depth-first search that
come immediately to mind if the tree represents, for example, a game strategy.
First, we might probe paths of game moves, starting with the leftmost unexplored
path, all the way to the end of the game to determine whether or not that path
was a winning strategy. In the case of a naive Sudoku solver, with each level being
a specific square to fill in and each node branching out to nine possible choices for
that square, we would encounter a very large number of search “crash” conditions
for illegal choices, and the entire tree below the node giving the crash would be
pruned away; we wouldn’t actually have to probe all the way to the end of the
game. One can imagine that this would be a simple program to write because it
would be a recursive call to a method that ran a couple of loops, and also that
it would be very inefficient because a large number of the paths would be illegal.
The program would spend most of its time in worthless looping and testing of
possibilities already shown to be illegal. We note that in this kind of search the
interior nodes don’t really have a part to play. Unlike the tree in Figure 10.20, in
which the interior nodes were the operations to be performed on the data in the
child nodes, in this kind of search the interior nodes contain no information other
than “more work to do” or “all subpaths already examined.”
The other kind of depth-first search tree is exemplified by a game such as chess. In
chess, there are too many possible moves to be able to explore any path all the way
to the end, but we also have, based on the knowledge of experts, a way to quantify
the “goodness” of any given board position. If we were to consider one move on
our part and then one response by the opponent, we could calculate the board’s
“goodness” for each move and response, and the purpose of our tree search would
be to choose our move so as to maximize the goodness. The goodness (or badness,
depending on one’s point of view) function is referred to in this kind of search as
an objective function to be minimized or maximized depending on the details.
The naive depth-first search, then, would probe down as many levels as was fea-
sible (competition chess games are timed, after all), compute the objective function
for the leaves at that level, and then minimize or maximize the objective function
as needed by applying a min or max function in the interior nodes of the tree.