Trees. 2 Definition of a tree A tree is like a binary tree, except that a node may have any number...

21
Trees

Transcript of Trees. 2 Definition of a tree A tree is like a binary tree, except that a node may have any number...

Trees

2

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

Each node contains an element and has branches leading to other nodes (its children)

Each node (other than the root) has a parent

Each node has a depth (distance from the root)

A

CB D E

GF H J KI

L M N

3

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

4

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 a Vector or an ArrayList or a LinkedList

class TreeNode { Object element; Vector<TreeNode> children;}

We can use an array, but that’s expensive if we need to add or delete children If the order of children is irrelevant, we may use a Set instead of a Vector If order of children matters, we cannot use a Set

5

General requirements for an ADT

The constructors and transformers must together be able to create all legal values of the ADT A constructor or transformer should never create an illegal

value It’s nice if the constructors alone can create all legal values,

but sometimes this results in constructors with too many parameters for reasonable convenience

The accessors must be able to extract any data needed by the application

6

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

7

A Tree ADT, I: Parents and values

Constructor: public Tree(Object value)

Values: public Object getValue() public void setValue(Object value)

Parents and ancestors: public Tree getParent() public boolean hasAncestor(Tree ancestor)

8

A Tree ADT, II: children and siblings

Children: public void addChild(Tree newChild) public void addChildren(ArrayList newChildren) public void detachFromParent()

public boolean hasChildren() public ArrayList getChildren() public Tree GetFirstChild() public Tree getLastChild()

Siblings: public boolean hasNextSibling() public Tree getNextSibling() public boolean hasPreviousSibling() public Tree getPreviousSibling()

9

A Tree ADT, III: Iterator, other methods

Iterator (preorder traversal of the Tree): public Iterator iterator() public boolean hasNext() public Object next() public void remove()

Convenience methods: public boolean isRoot() public boolean isLeaf() public int depth()

Standard methods: public boolean equals(Object o) public String toString() public void print()

10

Traversing a tree You can traverse a tree in preorder:

void preorderPrint(node) { // doesn’t use Tree.iterator() 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?

11

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

12

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

13

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 = mother and right child = father

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

14

Part of a genealogy

Isaac

DavidPaul

a

Steven Danielle

Winfred Carol

Chester Elaine Eugene Pauline

15

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

16

Binary trees for expressions

Ordered trees can be used to represent arithmetic expressions

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, Evaluate the children and combine them according to the operation

specified by the element

+

2 2The expression 2+2

+

2 *

3 4The expression 2+3*4

*

4+

2 3The expression (2+3)*4

17

(General) trees for expressions

You can use binary trees for expressions if you have only unary and binary operators

Java has a ternary operator

Trees can be used to represent statements as well as expressions

Statements can be evaluated as easily as expressions

The expression x > y ? x : y

?:

> x

x

y

y

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

y

if

>

xx y max max

= =

18

More trees for statements

while (n >= 1) { exp = x * exp; n--;}

for (int i = 0; i < n; i++) a[i] = 0;

while

>=

n 1

exp

exp

*

=

n

--

x

;

for

i

int

=

0

a

[ ]ii n 0

++

=<

i

19

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

20

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

21

The End