Binary trees have been used to model relationships for thousands of years. One reason for this is that binary trees naturally model (pedigree) family trees. These are the family trees in which the root is a person, the left and right children are the person's parents, and so on, recursively. In more recent centuries binary trees have also been used to model species trees in biology, where the leaves of the tree represent extant species and the internal nodes of the tree represent speciation events in which two populations of a single species evolve into two separate species.
Binary search trees appear to have been discovered independently by several groups in the 1950s [48, Section 6.2.2]. Further references to specific kinds of binary search trees are provided in subsequent chapters.
When implementing a binary tree from scratch, there are several design decisions to be made. One of these is the question of whether or not each node stores a pointer to its parent. If most of the operations simply follow a root-to-leaf path, then parent pointers are unnecessary, waste space, and are a potential source of coding errors. On the other hand, the lack of parent pointers means that tree traversals must be done recursively or with the use of an explicit stack. Some other methods (like inserting or deleting into some kinds of balanced binary search trees) are also complicated by the lack of parent pointers.
Another design decision is concerned with how to store the parent, left
child, and right child pointers at a node.  In the implementation given
here, these pointers are stored as separate variables.   Another option
is to store them in an array, 
 , of length 3, so that
, of length 3, so that 
![$ \mathtt{u.p[0]}$](img3291.png) is the
left child of
 is the
left child of 
 ,
, 
![$ \mathtt{u.p[1]}$](img3293.png) is the right child of
 is the right child of 
 , and
, and 
![$ \mathtt{u.p[2]}$](img3295.png) is
the parent of
 is
the parent of 
 .  Using an array this way means that some sequences
of
.  Using an array this way means that some sequences
of 
 statements can be simplified into algebraic expressions.
 statements can be simplified into algebraic expressions.
An example of such a simplification occurs during tree traversal. If
a traversal arrives at a node 
 from
 from 
![$ \mathtt{u.p[i]}$](img3299.png) , then the next node in
the traversal is
, then the next node in
the traversal is 
![$ \ensuremath{\mathtt{u.p}}[(\ensuremath{\mathtt{i}}+1)\bmod 3]$](img3300.png) .  Similar examples occur when
there is left-right symmetry.  For example, the sibling of
.  Similar examples occur when
there is left-right symmetry.  For example, the sibling of 
![$ \mathtt{u.p[i]}$](img3301.png) is
 is
![$ \ensuremath{\mathtt{u.p}}[(\ensuremath{\mathtt{i}}+1)\bmod 2]$](img3302.png) .  This trick works whether
.  This trick works whether 
![$ \mathtt{u.p[i]}$](img3303.png) is a left
child (
 is a left
child (
 ) or a right child (
) or a right child (
 ) of
) of 
 .  In some cases this
means that some complicated code that would otherwise need to have both a
left version and right version can be written only once. See the methods
.  In some cases this
means that some complicated code that would otherwise need to have both a
left version and right version can be written only once. See the methods
 and
 and 
 on page
 on page ![[*]](crossref.png) for an example.
for an example.
 nodes has
 nodes has 
 edges.
 edges.
 real nodes has
 real nodes has 
 external nodes.
  external nodes.
 , has at least one leaf, then either
  (a)
, has at least one leaf, then either
  (a)  's root has at most one child or (b)
's root has at most one child or (b)  has more than
  one leaf.
 has more than
  one leaf.
 , that computes the size
  of the subtree rooted at node
, that computes the size
  of the subtree rooted at node 
 .
.
 , that computes the height
  of node
, that computes the height
  of node 
 in a
 in a 
 .
.
 , the size of
  the subtrees rooted at
, the size of
  the subtrees rooted at 
 and
 and 
 differ by at most one.
  Write a recursive method,
 differ by at most one.
  Write a recursive method, 
 , that tests if a binary tree
  is balanced.  Your method should run in
, that tests if a binary tree
  is balanced.  Your method should run in 
 time.  (Be sure to
  test your code on some large trees with different shapes; it is easy
  to write a method that takes much longer than
 time.  (Be sure to
  test your code on some large trees with different shapes; it is easy
  to write a method that takes much longer than 
 time.)
 time.)
A pre-order traversal of a binary tree is a traversal that visits
each node, 
 , before any of its children.  An in-order traversal
visits
, before any of its children.  An in-order traversal
visits 
 after visiting all the nodes in
 after visiting all the nodes in 
 's left subtree but before
visiting any of the nodes in
's left subtree but before
visiting any of the nodes in 
 's right subtree.  A post-order
traversal visits
's right subtree.  A post-order
traversal visits 
 only after visiting all other nodes in
 only after visiting all other nodes in 
 's subtree.
The pre/in/post-order numbering of a tree labels the nodes of a tree with
the integers
's subtree.
The pre/in/post-order numbering of a tree labels the nodes of a tree with
the integers 
 in the order that they are encountered
by a pre/in/post-order traversal.  See Figure 6.10
for an example.
 in the order that they are encountered
by a pre/in/post-order traversal.  See Figure 6.10
for an example.
 whose nodes have fields for storing
  pre-order, post-order, and in-order numbers.  Write recursive methods
 whose nodes have fields for storing
  pre-order, post-order, and in-order numbers.  Write recursive methods
  
 ,
, 
 , and
, and 
 that
  assign these numbers correctly. These methods should each run in
 that
  assign these numbers correctly. These methods should each run in
  
 time.
 time.
 ,
, 
 , and
, and
  
 that return the node that follows
 that return the node that follows 
 in a pre-order,
  in-order, or post-order traversal, respectively.   These functions
  should take amortized constant time; if we start at any node
 in a pre-order,
  in-order, or post-order traversal, respectively.   These functions
  should take amortized constant time; if we start at any node
  
 and repeatedly call one of these functions and assign the return
  value to
 and repeatedly call one of these functions and assign the return
  value to 
 until
 until 
 , then the cost of all these calls should
  be
, then the cost of all these calls should
  be 
 .
.
 , determine the size of the subtree rooted at
, determine the size of the subtree rooted at 
 .
.
 , determine the depth of
, determine the depth of 
 .
.
 and
 and 
 , determine if
, determine if 
 is an ancestor of
 is an ancestor of 
 
 nodes can be represented
  using at most
 nodes can be represented
  using at most 
 bits.  (Hint: think about recording what
  happens during a traversal and then playing back that recording to
  reconstruct the tree.)
 bits.  (Hint: think about recording what
  happens during a traversal and then playing back that recording to
  reconstruct the tree.)
 and then 4.5 to
  the binary search tree in Figure 6.5.
 and then 4.5 to
  the binary search tree in Figure 6.5.
 and then 5 from
  the binary search tree in Figure 6.5.
 and then 5 from
  the binary search tree in Figure 6.5.
 method,
 method, 
 ,
  that returns a list of all items in the tree that are less than or
  equal to
,
  that returns a list of all items in the tree that are less than or
  equal to 
 .  The running time of your method should be
.  The running time of your method should be 
 where
  where 
 is the number of items less than or equal to
 is the number of items less than or equal to 
 and
 and 
 is the height of the tree.
  is the height of the tree.
 to an initially
  empty
 to an initially
  empty 
 in such a way that the resulting tree has
  height
 in such a way that the resulting tree has
  height 
 .  How many ways are there to do this?
.  How many ways are there to do this?
 and perform the operations
 and perform the operations 
 followed by
  followed by 
 (with the same value of
 (with the same value of 
 ) do we necessarily
  return to the original tree?
) do we necessarily
  return to the original tree?
 operation increase the height of any node in a
 operation increase the height of any node in a
  
 ?  If so, by how much?
?  If so, by how much?
 operation increase the height of any node in a
 operation increase the height of any node in a
  
 ?  Can it increase the height of the tree?  If so,
  by how much?
?  Can it increase the height of the tree?  If so,
  by how much?
 in which each node,
 in which each node,
  
 , maintains values
, maintains values 
 (the size of the subtree rooted at
 (the size of the subtree rooted at 
 ),
),
  
 (the depth of
 (the depth of 
 ), and
), and 
 (the height of the subtree
  rooted at
 (the height of the subtree
  rooted at 
 ).
).  
These values should be maintained, even during calls to the 
 and
  and 
 operations, but this should not increase the cost of
  these operations by more than a constant factor.
 operations, but this should not increase the cost of
  these operations by more than a constant factor.