Sei sulla pagina 1di 17

Trees

Definition of a tree
 A tree is like a binary tree, except that a node may have any
number of children
Depending on the needs of the program, the children may or may not be
ordered
 Like a binary tree, a tree has a
root, internal nodes, and leaves
A  Each node contains an element
and has branches leading to other
B C D E nodes (its children)
 Each node (other than the root)
F G H I J K has a parent
 Each node has a depth (distance
L M N from the root)

2
More definitions
 An empty tree has no nodes
 The descendents of a node are its children and the descendents
of its children
 The ancestors of a node are its parent (if any) and the
ancestors of its parent
 The subtree rooted at a node consists of the given node and all
its descendents
 An ordered tree is one in which the order of the children is
important; an unordered tree is one in which the children of a
node can be thought of as a set
 The branching factor of a node is the number of children it has
 The branching factor of a tree is the average branching factor
of its nodes

3
Data structure for a tree
 A node in a binary tree can be represented as follows:
class BinaryTreeNode {
Object value;
BinaryTreeNode leftChild, rightChild;
}

 However, each node in a tree has an arbitrary number of children,


so we need something that will hold an arbitrary number of
nodes, such as an ArrayList
class TreeNode {
Object value;
ArrayList children;
}

 If we don’t care about the order of children, we might use a Set


instead of a ArrayList

4
ADT for a tree
 It must be possible to:
 Construct a new tree
 If a tree can be empty, this may require a header node
 Add a child to a node
 Get (iterate through) the children of a node
 Access (get and set) the value in a node
 It should probably be possible to:
 Remove a child (and the subtree rooted at that child)
 Get the parent of a node

5
Traversing a tree
 You can traverse a tree in preorder:
void preorderPrint(node) {
System.out.println(node);
Iterator iter = node.children.iterator();
while (iter.hasNext()) {
preorderPrint(iter.next());
}
}
 You can traverse a tree in postorder:
void postorderPrint(node) {
Iterator iter = node.children.iterator();
while (iter.hasNext()) {
postorderPrint(iter.next());
}
System.out.println(node);
}
 You can’t usually traverse a tree in inorder
 Why not?
6
Other tree manipulations
 There’s really nothing new to talk about; you’ve
seen it all with binary trees

 A tree consists of nodes, each node has references


to some other nodes—you know how to do all this
stuff

 There are some useful algorithms for searching


trees, and with some modifications they also apply
to searching graphs

 Let’s move on to some applications of trees


7
File systems
 File systems are almost always implemented as a tree
structure
 The nodes in the tree are of (at least) two types: folders (or
directories), and plain files
 A folder typically has children—subfolders and plain files
 A folder also contains a link to its parent—in both Windows and
UNIX, this link is denoted by ..
 In UNIX, the root of the tree is denoted by /
 A plain file is typically a leaf

8
Family trees
 It turns out that a tree is not a good way to
represent a family tree
 Every child has two parents, a mother and a father
 Parents frequently remarry
 An “upside down” binary tree almost works
 Since it is a biological fact (so far) that every child has
exactly two parents, we can use left child = father and
right child = mother
 The terminology gets a bit confusing
 If you could go back far enough, it becomes a
mathematical certainty that the mother and father have
some ancestors in common

9
Part of a genealogy

Isaac

Steven Danielle

Paul
David Winfred Carol
a

Chester Elaine Eugene Pauline

10
Game trees
 Trees are used heavily in implementing games, particularly
board games
 A node represents a position on the board
 The children of a node represent all the possible moves from
that position
 More precisely, the branches from a node represent the possible moves;
the children represent the new positions
 Planning ahead (in a game) means choosing a path through the
tree
 However—
 You can’t have a cycle in a tree
 If you can return to a previous position in a game, you have a cycle
 Graphs can have cycles

11
Binary trees for expressions
 Ordered trees can be used to represent arithmetic expressions
+ + *
2 2 2 * + 4
The expression 2+2
3 4 2 3
The expression 2+3*4 The expression (2+3)*4

 To evaluate an expression (given as a node):


 If it is a leaf, the element in it specifies the value
 If the element is a number, that number is the value
 If the element is a variable, look up its value in a table
 If it is not a leaf, the element in it specifies an operation
 Evaluate the children and combine them according to the operation

12
(General) trees for expressions
 You can use binary trees for expressions if you have only unary
and binary operators
 Java has a ternary operator
?: if

> x y > = =

x y x y max x max y
The expression x > y ? x : y The statement if (x > y) max = x;
else max = y;

 Trees can be used to represent statements as well as


expressions
 Statements can be evaluated as easily as expressions

13
More trees for statements
while (n >= 1) { for (int i = 0; i < n; i++)
exp = x * exp; a[i] = 0;
n--;
}
for
while
= < ++ =
>= ;

n 1 = -- int 0 i n i [] 0

exp * n i a i

x exp

14
Writing compilers and interpreters
 A compiler does three things:
 Parses the input program (converts it into an abstract syntax tree)
 (Optionally) optimizes the abstract syntax tree
 Traverses the tree and outputs assembly language or machine code
to do the same operations
 An interpreter does three things:
 Parses the input program (converts it into an abstract syntax tree)
 (Optionally) optimizes the abstract syntax tree
 Traverses the tree in an order controlled by the node contents, and
performs the operations as it goes
 Parsing is usually the hard part, but there is a very simple
technique (called recursive descent parsing) that can be
used if the language is carefully designed and you don’t
care too much about efficiency or good error messages

15
I’ll never need to write a compiler...
 Are you sure?
 If you can’t parse text inputs, you are limited to reading simple
things like numbers and Strings
 If you can parse text input, you can make sense of:
 tell Mary "Meet me at noon"
 fire phasers at 3, 7
 17.25, 0.203 + 8.97i, 0.95i
 28°12"48'
 3:30pm-5pm
 Parsing is less important in these days of GUIs, but it’s still pretty
important
 Java provides basic support for parsing with its StringTokenizer and
StreamTokenizer classes

16
The End

17

Potrebbero piacerti anche