Trees, Part 1

1 / 75

# Trees, Part 1 - PowerPoint PPT Presentation

Trees, Part 1. CSCI 2720 University of Georgia Spring 2007. Tree Properties and Definitions. Composed of nodes and edges Node Any distinguishable object Edge An ordered pair <u,v> of nodes Illustrated by an arrow with tail at u and head at v u = tail of <u,v>

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about 'Trees, Part 1' - austin

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### Trees, Part 1

CSCI 2720

University of Georgia

Spring 2007

Tree Properties and Definitions
• Composed of nodes and edges
• Node
• Any distinguishable object
• Edge
• An ordered pair of nodes
• Illustrated by an arrow with tail at u and head at v
• u = tail of
• Root
• A distinguished node, depicted at the top of the tree
Recursive Definition of a Tree
• A single node, with no edges, is a tree. The root of the tree is its unique node.
• Let T1, …, Tk (k >=1) be trees with no nodes in common, and let r1, …,rk be the roots of those trees, respectively. Let r be a new node. Then there is a tree T consisting of the nodes and edges of T1, …, Tk , the new node r and the edges ,…,. The root of T is r and T1, …,Tk are called the subtrees of T.
Tree definitions and terminology
• r is called the parent of r1, …, rk
• r1, …, rk are the children of r
• r1, …, rk are the siblings of one another
• Node v is a descendant of u if
• u = v or
• v is a descendant of a child of u
• A path exists from u to v.
Recursive definition

Before:

The trees T1, …, Tk, with roots r1, …, rk

After:

new tree T rooted at r with subtreesT1, …, Tk,

What do we mean by a path from u to v?
• You can get from u to v by following a sequences of edges down the tree, starting with an edge whose tail is u, ending with an edge whose head is v, and with the head of each edge but the last being the tail of the next.
Tree terminology
• Every node is a descendant of itself.
• If v is a descendant of u, then u is an ancestor of v.
• Properdescendants:
• The descendants of a node, other than the node itself.
• Proper ancestors
• The ancestors of a node, other than the node itself.
Tree terminology & properties
• Leaf
• a node with no children
• Num_nodes = Num_edges + 1
• Every tree has exactly one more node than edge
• Every edge, except the root, is the head of exactly one of the edges
Tree terminology & properties
• Height of a node in a tree
• Length of the longest path from that node to a leaf
• Depth of a node in a tree
• Length of the path from the root of the tree to the node
Tree terminology

root

root

leaf

leaf

leaf

leaf

leaf

leaf

Tree terminology

u

v

A path from u to v. Node u is the ancestor of node v.

Tree terminology
• w has depth 2
• u has height 3
• tree has height 4

u

w

Special kinds of trees
• Ordered v. unordered
• Binary tree
• Empty v non-empty
• Full
• Perfect
• Complete
Ordered trees
• Have a linear order on the children of each node
• That is, can clearly identify a 1st, 2nd, …, kth child
• An unordered tree doesn’t have this property
Binary tree
• An ordered tree with at most two children for each node
• If node has two child, the 1st is called the left child, the 2nd is called the right child
• If only one child, it is either the right child or the left child

Two trees are not equivalent …One has only a left child; the other has only a right child

Empty binary tree
• Convenient to define an empty binary tree, written , for use in this definition:
• A binary tree is either  or is a node with left and right subtrees, each of which is a binary tree.
Full binary tree
• Has no nodes with only one child
• Each node either a leaf or it has 2 children
• # leaves = #non-leaves + 1
Perfect binary tree
• A full binary tree in which all leaves have the same depth
• Perfect binary tree of height h has:
• 2h+1 -1 nodes
• 2h leaves
• 2h -1 non-leaves
• Interesting because it is “fully packed”, the shallowest tree that can contain that many nodes. Often, we’ll be searching from the root. Such a shallow tree gives us minimal number of accesses to nodes in the tree.
Complete binary tree
• Perfect binary tree requires that number of nodes be one less than a power of 2.
• Complete binary tree is a close approximation, with similar good properties for processing of data stored in such a tree.
• Complete binary tree of height h:
• Perfect binary tree of height h-1
• Add nodes from left at bottom level
More formally, …
• A complete binary tree of height 0 is any tree consisting of a single node.
• A complete binary tree of height 1 is a tree of height 1 with either two children or a left child only.
• For height h >= 2, a complete binary tree of height h is a root with two subtrees satisfying one of these two conditions:
• Either the left subtree is perfect of height h-1 and the right is complete of height h-1 OR
• The left is complete of height h-1 and the right is perfect of height h-2.
Tree terminology
• Forest
• A finite set of trees
• In the case of ordered trees, the trees in the forest must have a distinguishable order as well.
Tree Operations
• Parent(v)
• Children(v)
• FirstChild(v)
• RightSibling(v)
• LeftSibling(v)
• LeftChild(v)
• RightChild(v)
• isLeaf(v)
• Depth(v)
• Height(v)
Parent(v)
• Return the parent of node v, or  if v is the root.
Children(v)
• Return the set of children of node v (the empty set, if v is a leaf).
FirstChild(v)
• Return the first child of node v, or  if v is a leaf.
RightSibling(v)
• Return the right sibling of v, or  if v is the root or the rightmost child of its parent.
LeftSibling(v)
• Return the left sibling of v, or  if v is the root or the leftmost child of its parent
LeftChild(v)
• Return the left child of node v;
• Return  if v has no left or right child.
RightChild(v)
• Return the right child of node v;
• return  if v has no right child
isLeaf(v)
• Return true if node v is a leaf, false if v has a child
Depth(v)
• Return the depth of node v in the tree.
Height(v)
• Return the height of node v in the tree.
Arithmetic Expression Tree
• Binary tree associated with an arithmetic expression
• internal nodes: operators
• external nodes: operands
• Example: arithmetic expression tree for the infix expression:
• (2 × (a − 1) + (3 × b))
• Note: infix expressions require parentheses
• ((2 x a) – (1+3) * b) is a different expression tree
Evaluating Expression Trees

function Evaluate(ptr P): integer

/* return value of expression represented by tree with root P */

if isLeaf(P) return Label(P)

else

xL <- Evaluate(LeftChild(P))

xR <- Evaluate(RightChild(P))

op <- Label(P)

return ApplyOp(op, xL, xR)

Example

- Evaluate (A)

Evaluate(B)

Evaluate(D) => 2

Evaluate(E)

Evaluate(H)=> a

Evaluate(I) => 1

ApplyOp(-,a,1) => a-1

ApplyOp(x,2,(a-1)) => (2 x (a-1))

Evaluate(C)

Evaluate(F) => 3

Evaluate(G) => b

ApplyOp(x,3,b) => 3 x b

ApplyOp(+,(2 x (a-1)),(3 x b)) =>

(2 x (a-1)) + (3 x b)

A

B

C

F

G

E

D

H

I

Traversals
• Traversal = any well-defined ordering of the visits to the nodes in a tree
• PostOrder traversal
• Node is considered after its children have been considered
• PreOrder traversal
• Node is considered before its children have been considered
• InOrder traversal (for binary trees)
• Consider left child, consider node, consider right child
PostOrder Traversal

procedurePostOrder(ptr P):

foreach childQ of P, in order, do

PostOrder(Q)

Visit(P)

PostOrder traversal gives:

2, a, 1, -, x, 3, b, x, +

Nice feature: unambiguous … doesn’t need parentheses

-- often used with scientific calculators

-- simple stack-based evaluation

Evaluating PostOrder Expressions

procedurePostOrderEvaluate(e1, …, en):

forifrom 1 to ndo

ifei is a number, then push it on the stack

else

• Pop the top two numbers from the stack
• Apply the operator ei to them, with the right operand being the first one popped
• Push the result on the stack
PreOrder Traversal

procedurePreOrder(ptr P):

Visit(P)

foreach childQ of P, in order, do

PreOrder(Q)

PreOrder Traversal:

+, x, 2, -, a, 1, x, 3, b

Nice feature: unambigous, don’t need parentheses

-- Outline order

InOrder Traversal

procedureInOrder(ptr P):

// P is a pointer to the root of a binary tree

if P =  then return

else

InOrder(LeftChild(P))

Visit(P)

InOrder(RightChild(P))

InOrder Traversal:

2 x a – 1 + 3 x b

Binary Search Trees
• Use binary trees to store data that is linearly ordered
• A linear order is a relation < such that for any x, y, and z
• If x and y are different then either x
• If x
• An inorder traversal of a binary search tree yields the labels on the nodes, in linear order.
Binary Search Trees, examples

50

60

30

70

20

40

Inorder traversal yields: 20, 30, 40, 50, 60, 70

Level-order traversal

A

C

B

F

D

E

A, B, C, D, E, F

Tree Implementations
• General Binary Tree
• General Ordered Trees
• Complete Binary Trees
Binary Trees:“Natural Representation”
• LC : contains pointer to left child
• RC: contains pointer to right child
• Info: contains info or pointer to info
• LeftChild(p), RightChild(p): (1)
• Parent(p): not (1) unless we also add a parent pointer to the node

LC info RC

• Parent(p): not (1) unless we also add a parent pointer to the node
• Can use xor trick to store parent-xor-left,
• Parent-xor-right, and use only two fields
Ordered Tree representation
• Binary tree: array of 2 ptrs to 2 children
• Ternary tree: array of 3 ptrs to 3 children
• K-ary trees: k pointers to k children
• What if there is no bound on the number of children?
• Use binary tree representation of ordered tree:

First Info Right

Child Sibling

General ordered tree

Binary tree rep

Example

A

A

B

B

C

D

C

E

D

F

E

F

G

H

I

G

H

I

Complete Binary Tree: Implicit representation

Binary Search Trees, example

50

70

30

20

40

60

0 1 2 3 4 5

[50 | 30 | 70 | 20 | 40| 60]

Implicit rep of complete binary trees
• isLeaf(i) :
• 2i + 1 >= n
• LeftChild(i) :
• 2i + 1 (none if 2i + 1 >= n)
• RightChild(i) :
• 2i + 2 (none if 2i + 2 >= n)
LeftSibling(i):
• i-1 (none if i=0 or i is odd)
• RightSibling(i):
• i+1 (none if i=n-1 or i is even)
• Parent(i):
• floor((i-1)/2) (none if i=0)
Depth(i):
• floor (lg(i+1))
• Height(i):
• ceil(lg((n+1)/(i+1))) - 1
Tree Traversals and Scans
• Stack-based Traversals
• Scanning in Constant Space
• Level-Order Traversal
procedure Traverse(ptr P)

//traverse binary tree with root P

if P !=  then

PreVisit(P)

Traverse(LC(P))

InVisit(P)

Traverse(RC(P))

PostVisit(P)

Provide functions for Previsit(P),Invisit(P), and/or PostVisit(P)

Some can be null (do-nothing) functions

Implements all 3 traversal (inorder, preorder, postorder) … just depends on which functions have “real” bodies

Stack-based Traversals
procedure Traverse(ptr P)

//traverse binary tree with root P

if P !=  then

PreVisit(P)

Traverse(LC(P))

InVisit(P)

Traverse(RC(P))

PostVisit(P)

O(n) time to visit all nodes

Height of the stack is proportional to the height of the tree

If structure is large, height of stack can be problematic

For pre-order and inorder, one of the calls to Traverse is tail-recursive & we can eliminate it

Stack-based Traversals
procedure Traverse(ptr P)

//traverse binary tree with root P

if P !=  then

PreVisit(P)

Traverse(LC(P))

InVisit(P)

Traverse(RC(P))

PostVisit(P)

procedure Traverse(ptr P)

//traverse binary tree with root P

While P !=  do

PreVisit(P)

Traverse(LC(P))

InVisit(P)

P <- RC(P)

- demo difference in stack heights for small example

Stack-based Traversals
How high does the stack get for this alg?

Depends on “max left height” -- proportional to the height of the corresponding ordered tree

OrdHt(P):

if P = 

0

if LC(P) == 

OrdHt(RC(P))

Otherwise

Max(1 + OrdHt(LC(P)), OrdHt(RC(P)))

Example: calculate ordered height for medium-sized BT

Height of stack for “improved” algorithm
• Use same ideas from link-inversion traversal of list
• Stores contents of stack in tree itself
• Use tag bit to indicate whether to follow LC or RC at this point

tag LC info RC

• Tag also indicates:
• When recursive invocation finishes
• Which of the two recursive calls in the body caused that invocation
• Where in the body the execution should continue

// initially Q points to root

P <- 

repeat forever

// descend to left afap

while Q !=  do

PreVisit(Q)

Tag(Q) <- 0

descend_to_left

// ascend from right afap

while P !=  and Tag(P) == 1 do

ascend_from_right

PostVisit(Q)

if P == then return

else

ascend_from_left

InVisit(Q)

Tag(Q) <- 1

descend_to_right

descend_to_left

ascend_from_left

descend_to_right

Ascend_from_right

Ascend/ Descend functions
Example
• Demo on small - midsized tree
One more twist
• Actually, don’t really need to store the tag bits in the nodes themselves … can just place them in a stack at the time the algorithm runs!
Scanning in Constant Space
• Can visit each node in a tree, at least once, using only a few temporary variables
• Catch: not a standard traversal order
• In fact - visits each node three times
• “walks around” the tree, keeping nodes and edges to its left
Constant Space Scan

50, 30, 20, 20, 20, 30, 40, 40, 40, 30, 50, 70, 60, 60, 60, 70, 70, 50

50, 30, 20, 40, 70, 60

20 30 40 50 60 70

20 40 30 60 70 50

Trees, example

50

70

30

20

40

60

Constant Space Scan

procedure ConstantSpaceScan(ptr Q):

 is a distinguished value

Initially Q points to root

P <- 

While Q !=  do

If Q !=  then

Visit(Q)

else

P <-> Q

• Inorder traversal is a common operation
• Require extra memory to store a stack
• Can’t start from an arbitrary node … need to start at the root
• Want to make it easier to find inorder successor of a node
• Inorder predecessor would be nice too!

100

200 | 40 | 300

40

200

30

50

300

400 | 30 | 

 | 50 | 500

400

500

10

60

 | 10 | 600

 | 60| 

600

20

 | 20 | 

Hmmmm … that’s quite a few null pointers!

In fact, in binary tree with n nodes, there are 2n pointers .. And n+1 of these are  … maybe we can make use of this memory ….

• If a node has no right child, store a pointer to the node’s inorder successor
• If a node has no left child, store a pointer to the node’s inorder predecessor
• Need to keep a threat bit to distinguish between “regular” pointers and threads

100

200 | 40 | 300

40

200

30

50

300

400 | 30 | 

 | 50 | 500

400

500

10

60

 | 10 | 600

 | 60| 

600

20

 | 20 | 

On board .. Sketch out threaded equivalent of this tree ….

InOrder Successor

function InorderSuccessor(ptr N): ptr

//return the inorder successor of N or  if none exists

P <- RC(N)

if P =  then return 

else if P is not a thread then

while LC(P) is not a thread or  do

P <- LC(P)

return P

// Make node Q the inorder successor of node P

if RC(Q) is not a thread then

100

200 | 40 | 300

200

300

400 | 30 | 

 | 50 | 500

400

500

 | 10 | 600

 | 60| 

600

 | 20 | 

Level-Order Traversal

Procedure LevelOrder(ptr R):

//R is a ptr to the root of the tree

L <- MakeEmptyQueue()

Enqueue(R, L)

Until IsEmptyQueue(L)

P <- Dequeue(L)

Visit(P)

Foreach child Q of P, in order, do

Enqueue(Q,L)