Introduction To Trees
Introduction To Trees
Introduction To Trees
Introduction
Lists, stacks, and queues, are all linear structures: in all three data structures, one item
follows another. Trees will be our first non-linear structure:
The number of items that follow can vary from one item to another.
the bottom nodes (with no outgoing edges) are the leaves (nodes D, I, G & J)
So a (computer science) tree is kind of like an upside-down real tree...
A path in a tree is a sequence of (zero or more) connected nodes; for example, here
are 3 of the paths in the tree shown above:
The height of a tree is the length of the longest path from the root to a leaf; for the
above example, the height is 4 (because the longest path from the root to a leaf is A →
C → E → G, or A → C → E → J). An empty tree has height = 0.
The depth of a node is the length of the path from the root to that node; for the above
example:
the depth of J is 4
the depth of D is 3
the depth of A is 1
A subtree of a given node includes one of its children and all of that
child's descendants. The descendants of a node n are all nodes reachable from n (n's
children, its children's children, etc.). In the original example, node A has three
subtrees:
1. B, D
2. I
3. C, E, F, G, J.
The two trees are different because the children of node B are different: in the first
tree, B's left child is D and its right child is E; in the second tree, B's left child is E and
its right child is D. Also note that lines are used instead of arrows. We sometimes do
this because it is clear that the edge goes from the higher node to the lower node.
Representing Trees
Since a binary-tree node never has more than two children, a node can be represented
using a class with 3 fields: one for the data in the node, plus two child pointers:
class BinaryTreenode {
// *** fields ***
private Object data;
private BinaryTreenode leftChild;
private BinaryTreenode rightChild;
}
However, since a general-tree node can have an arbitrary number of children, a fixed
number of child-pointer fields won't work. Instead, we can use a List to keep all of the
child pointers:
class Treenode {
// *** fields ***
private Object data;
private List children;
}
(Note that the items in the List will be of type Treenode.)
For the array representation of the List (where the array has an initial size of 4) we
would have:
TEST YOURSELF #1
Draw a similar picture of the tree when the List fields are implemented using linked
lists.
solution
Tree Traversals
It is often useful to iterate through the nodes in a tree:
to make a copy
When we iterated through a List, we started with the first node and visited each node
in turn. Since each node is visited, the best possible complexity is O(N) for a tree with
N nodes. All of our traversal methods will achieve this complexity.
For trees, there are many different orders in which we might visit the nodes. There are
three common traversal orders for general trees, and one more for binary trees:
preorder, postorder, level order, and in-order, all described below. We will use
the following tree to illustrate each traversal:
Preorder
If we use a preorder traversal on the example tree given above, and we print the letter
in each node when we visit that node, the following will be printed: A B D C E G F H
I.
Postorder
A postorder traversal is similar to a preorder traversal, except that the root of each
subtree is visited last rather than first:
1. perform a postorder traversal of the first subtree of the root
If we use a postorder traversal on the example tree given above, and we print the letter
in each node when we visit that node, the following will be printed: D B G E H I F C
A.
Level order
The idea of a level-order traversal is to visit the root, then visit all nodes "1 level
away" (depth 2) from the root (left to right), then all nodes "2 levels away" (depth 3)
from the root, etc. For the example tree, the goal is to visit the nodes in the following
order:
TEST YOURSELF #2
Draw pictures of Q as it would be each time around the outer while loop in the code
given above for the example tree given above.
solution
In-order
An in-order traversal involves visiting the root "in between" visiting its left and right
subtrees. Therefore, an in-order traversal only makes sense for binary trees. The
(recursive) definition is:
If we print the letters in the nodes of our example tree using an in-order traversal, the
following will be printed: D B A E G C H F I
The primary difference between the preorder, postorder and in-order traversals is
where the node is visited in relation to the recursive calls; i.e., before, after or in-
between.
TEST YOURSELF #3
What is printed when the following tree is visited using (a) a preorder traversal, (b) a
postorder traversal, (c) a level-order traversal, and (d) an in-order traversal?