trees
DESCRIPTION
Trees. Graphs. List and trees belong to a broader set of structures called graphs: G = (V,E) V = vertex set E = edge set. Graphs. What graph is represented by this linked list? A --> B --> C --> D --> E. Graphs. What graph is represented by this linked list? A --> B --> C --> D --> E - PowerPoint PPT PresentationTRANSCRIPT
Trees
Graphs
List and trees belong to a broader set of structures called graphs:
G = (V,E) V = vertex set E = edge set
Graphs
What graph is represented by this linked list?
A --> B --> C --> D --> E
Graphs
What graph is represented by this linked list?
A --> B --> C --> D --> E
G = (V,E)V = { A, B, C, D, E }E = { <A,B>, <B,C>, <C,D>, <D,E> }
Digraphs
Graphs can either be directed (digraph) or undirected.A <--> B <--> C - undirectedA --- B --- C - undirected
A <-- B --> C - directed
We will restrict the remainder of our discussion to digraphs.
Representing digraphs
We represented our digraph with a linked list structure.
We can also represent a digraph with an incidence matrix.
to
A B C D E
A X
B X
from C X
D X
E
What is the underlying graph for this doubly linked list?
A B C D E
What is the underlying graph for this doubly linked list?
A B C D EG = (V,E)
V = { A, B, C, D, E }E = { <A,B>, <B,A>, <B,C>, <C,B>, <C,D>, <D,C>, <D,E>, <E,D> }
What is the corresponding incidence matrix?
What is the underlying graph for this doubly linked list?
A B C D E
to
A B C D E
A X
from B X X
C X X
D X X
E X
Is that all there is (i.e., singly linked or doubly linked lists)?
A B C D E
Note that we can have one link per node.
Trees Special node called the root node.
Appears at top of tree by convention. Terminal nodes are called leaf nodes. A special type of graph called a tree (AKA
arborescence) = digraph w/ exactly 1 path from root to all other nodes.
A set of trees is called a forest. Arity = max branching factor per node
Arity of 2 is called a binary tree
Tree example
A
B C
D E F
G H ISubtree rooted at node E.
root node
Representing trees
A
B C
D E F
G H ICan we represent the tree with an incidence matrix?
to
A B C D E F G H I
A X X
B X X
C X
D Xfrom
E X X
F
G
H
I
Representing trees
A
B C
D E F
G H I
Representing trees
A
B C
D E F
G H I How can we represent a tree as a linked structure?
leftlink
rightlink
Representing trees
A
B C
D E F
G H I
public class MyTree {private class Node {
int mData;Node mLeft;Node mRight;
}private Node mRoot;
}
Visiting nodes in a tree
There are 3 ways do visit (process) the nodes in a tree: preorder, inorder, and postorder.
Preorder1. Process data in current node2. Process left subtree3. Process right subtree An example of a recursive definition
Visiting nodes in a tree
Inorder1. Process left subtree2. Process data in current node3. Process right subtree An example of a recursive definition
Visiting nodes in a tree
Postorder1. Process left subtree2. Process right subtree3. Process data in current node An example of a recursive definition
Representing trees
A
B C
D E F
G H I Preorder:A B D G E H I C F
Preorder1. Process data in current
node2. Process left subtree3. Process right subtree
Representing trees
A
B C
D E F
G H I Inorder: G D B H E I A F C
Inorder1. Process left subtree2. Process data in current
node3. Process right subtree
Representing trees
A
B C
D E F
G H I Postorder: G D H I E B F C A
Postorder1. Process left subtree2. Process right subtree3. Process data in current
node
Trees? G = (V,E) where
V={} and E={}? V={A} and E={}? V={A} and E={<A,A>}? V={A,B} and E={<A,B>}? V={A,B,C} and E={ <A,B>, <A,C> }? V={A,B,C} and E={ <A,B>, <B,C> }? V={A,B,C,D} and E={ <B,C>, <B,D> }? V={A,B,C,D,E} and E={ <A,B>,<A,C>,<D,E>
}?
Binary Search Trees (BST)
For every subtree rooted at some node n w/ value v, all elements to the left are less than v and all elements to the right are greater than v.
BST example
5
3
BST example
5
3 92
BST example
10
5 15
1 7 11 62
40 70
Operations on BSTs
1. Search/find/contains2. Add3. Remove
class Node {int mData;Node mLeft = null;Node mRight = null;Node ( int value ) { mData = value; }
}
Operations on BSTs
class MyBST {private Node mRoot = null;public boolean contains ( int value ) {
…}
}
Operations on BSTsclass MyBST {
private Node mRoot = null;public boolean contains ( int value ) {Node n = mRoot;while (n!=null) {if (n.mData==value) return true;else if (value<n.mData) n = n.mLeft;else n = n.mRight;}return false;}
}
Operations on BSTs
class MyBST {private Node mRoot = null;public boolean containsRecursive ( int value ) {
…}
}
Operations on BSTs
class MyBST {private Node mRoot = null;public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );}public boolean containsRecursive ( int value, Node n ){
…}
}
Specifies the subtree to search.
BEGIN RECURSION REVIEW
n! (n factorial) The number of ways n objects can be
permuted (arranged). For example, consider 3 things, A, B,
and C. 3! = 61. ABC2. ACB3. CAB4. CBA5. BCA6. BAC
The first few factorials for n=0, 1, 2, ... are 1, 1, 2, 6, 24, 120, ...
n! (n factorial) n! for some non negative integer n is
defined as: n! = n * (n-1) * (n-2) * … * 2 * 1 0! is defined as 1.
From http://mathworld.wolfram.com/Factorial.html
n! (n factorial)
n! for some non negative integer n can be rewritten as: 0! = 1 for n = 0 1! = 1 for n = 1 n! = n * (n-1)! for all other n > 1
Triangular numbers The triangular number Tn can be
represented in the form of a triangular grid of points where the first row contains a single element and each subsequent row contains one more element than the previous one. The triangular numbers are therefore 1, 1+2, 1+2+3, 1+2+3+4, ..., so the first few triangle numbers are 1, 3, 6, 10, 15, 21, ...
Triangular numbers
which can also be expressed as: Tn = 1 for n = 1 Tn = n + Tn-1 for n > 1
From http://mathworld.wolfram.com/TriangularNumber.html
n
kn kT
0
Triangular numbers
A plot of the first few triangular numbers represented as a sequence of binary bits is shown below. The top portion shows T1 to T255, and the bottom shows the next 510 values.
Fibonacci numbers
The sequence of Fibonacci numbers begins: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ...
21
2
1
2
1
nnn FFF
F
F
Back to n! (n factorial)
n! for some non negative integer n can be rewritten as: 0! = 1 for n = 0 1! = 1 for n = 1 n! = n * (n-1)! for all other n > 1
base cases
inductive case
Let’s code n! (n factorial) n! for some non negative integer n can
be rewritten as: 0! = 1 for n = 0 1! = 1 for n = 1 n! = n * (n-1)! for all other n > 1
public static int nFactorial ( int n ) {
}
base cases
inductive case
Let’s code n! (n factorial) n! for some non negative integer n can
be rewritten as: 0! = 1 for n = 0 1! = 1 for n = 1 n! = n * (n-1)! for all other n > 1
public static int nFactorial ( int n ) {//base casesif (n==0) return 1;
}
base cases
inductive case
Let’s code n! (n factorial) n! for some non negative integer n can
be rewritten as: 0! = 1 for n = 0 1! = 1 for n = 1 n! = n * (n-1)! for all other n > 1
public static int nFactorial ( int n ) {//base casesif (n==0) return 1;if (n==1) return 1;
}
base cases
inductive case
Let’s code n! (n factorial) n! for some non negative integer n can
be rewritten as: 0! = 1 for n = 0 1! = 1 for n = 1 n! = n * (n-1)! for all other n > 1
public static int nFactorial ( int n ) {//base casesif (n==0) return 1;if (n==1) return 1;return n * nFactorial( n-1 );
}
base cases
inductive case
Let’s code n! (n factorial) n! for some non negative integer n can
be rewritten as: 0! = 1 for n = 0 1! = 1 for n = 1 n! = n * (n-1)! for all other n > 1
public static int nFactorial ( int n ) {//base casesif (n==0) return 1;if (n==1) return 1;return n * nFactorial( n-1 );
}
This is an example of a recursive function (a function that calls itself)!
To use this function:
int result = nFactorial( 10 );
Back to Triangular numbers
Tn = 1 for n = 1 Tn = n + Tn-1 for n > 1
What is the base case(s)? What is the inductive case? How can we write the code for this?
Back to Fibonacci numbers
The sequence of Fibonacci numbers begins: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ...
21
2
1
2
1
nnn FFF
F
FWhat is the base case(s)?
What is the inductive case?
How can we code this?
A note regarding recursion . . .
Calculations such as factorial, Fibonacci numbers, etc. are fine for introducing the idea of recursion.
But the real power of recursion (IMHO) is in traversing advanced data structures such as trees (covered in more advanced classes and used in such as applications as language parsing, games, etc.).
END RECURSION REVIEW
Recursion
When a function calls itself. If unrestricted, this will go on “forever.” Base case(s)
Restriction(s) to avoid forever Typically what we should do when the
value is null, 1, 0, the first value, and/or the last value.
Recursive case(s) Actual recursive function call
Operations on BSTsclass MyBST {
private Node mRoot = null;public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );}public boolean containsRecursive ( int value, Node n ){
//base case(s)…
}}
Base case: What should we do when n is null?
Operations on BSTsclass MyBST {
private Node mRoot = null;public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );}public boolean containsRecursive ( int value, Node n ){
//base case(s)if (n==null) return false;…
}}
Operations on BSTsclass MyBST {
private Node mRoot = null;public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );}public boolean containsRecursive ( int value, Node n ){
//base case(s)if (n==null) return false;…
}}
Base case: What should we do if we find the value?
Operations on BSTsclass MyBST {
private Node mRoot = null;public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );}public boolean containsRecursive ( int value, Node n ){
//base case(s)if (n==null) return false;if (n.mData==value) return true;…
}}
Operations on BSTsclass MyBST {
private Node mRoot = null;public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );}public boolean containsRecursive ( int value, Node n ){
//base case(s)if (n==null) return false;if (n.mData==value) return true;…
}}
Recursive case: What should we do if value is less than n.mData? (Where will the data have to be then?)
Operations on BSTsclass MyBST {
private Node mRoot = null;
public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );
}
public boolean containsRecursive ( int value, Node n )
{
//base case(s)
if (n==null) return false;
if (n.mData==value) return true;
//recursive case(s)
if (value<n.mData)
return containsRecursive( value, n.mLeft );
…
}
}
Operations on BSTsclass MyBST {
private Node mRoot = null;
public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );
}
public boolean containsRecursive ( int value, Node n )
{
//base case(s)
if (n==null) return false;
if (n.mData==value) return true;
//recursive case(s)
if (value<n.mData)
return containsRecursive( value, n.mLeft );
…
}
}
Recursive case: What remains?
Operations on BSTsclass MyBST {
private Node mRoot = null;
public boolean containsRecursive ( int value ) {
return containsRecursive( value, mRoot );
}
public boolean containsRecursive ( int value, Node n )
{
//base case(s)
if (n==null) return false;
if (n.mData==value) return true;
//recursive case(s)
if (value<n.mData)
return containsRecursive( value, n.mLeft );
return containsRecursive( value, n.mRight );
}
}
Operations on BSTs containsRecursive isn’t really any better
than contains. So one may question the value of
recursion. Consider a toString method for a BST
that returns a string of all of the values of mData in order. With recursion, this is trivial. Without recursion, this is extremely difficult.
Recursive toString method for BSTs
Inorder:1. Process left subtree2. Process data in current node3. Process right subtree
Recursive toString method for BSTsclass MyBST {
private Node mRoot = null;public String toString ( ) {
return toString( mRoot );}//Inorder: Process left subtree// Process data in current node// Process right subtreepublic String toString ( Node n ) {
//base case(s)…//recursive case(s)
}}
Recursive toString method for BSTsclass MyBST {
private Node mRoot = null;public String toString ( ) {
return toString( mRoot );}//Inorder: Process left subtree// Process data in current node// Process right subtreepublic String toString ( Node n ) {
//base case(s)…//recursive case(s)
}}
What is the base case(s)?
Recursive toString method for BSTsclass MyBST {
private Node mRoot = null;public String toString ( ) {
return toString( mRoot );}//Inorder: Process left subtree// Process data in current node// Process right subtreepublic String toString ( Node n ) {
//base case(s)if (n==null) return “”;//recursive case(s)
}}
Recursive toString method for BSTsclass MyBST {
private Node mRoot = null;public String toString ( ) {
return toString( mRoot );}//Inorder: Process left subtree// Process data in current node// Process right subtreepublic String toString ( Node n ) {
//base case(s)if (n==null) return “”;//recursive case(s)
}}
What is the recursive case(s)?
Recursive toString method for BSTsclass MyBST {
private Node mRoot = null;public String toString ( ) {
return toString( mRoot );}//Inorder: Process left subtree// Process data in current node// Process right subtreepublic String toString ( Node n ) {
//base case(s)if (n==null) return “”;//recursive case(s)return toString( n.mLeft ) + “ “ + n.mData + “ “ + toString( n.mRight );
}}
Recursive toString method for BSTsclass MyBST {
private Node mRoot = null;public String toString ( ) {
return toString( mRoot );}//Inorder: Process left subtree// Process data in current node// Process right subtreepublic String toString ( Node n ) {
//base case(s)if (n==null) return “”;//recursive case(s)return toString( n.mLeft ) + “ “ + n.mData + “ “ + toString( n.mRight );
}}
Try to do this w/out using recursion!
Modify this to: 1. have just one node per line 2. be preorder 3. indent each line according to
depth of node in treeThis represents the structure of our tree (sideways).
Recursive toString method for BSTsclass MyBST {
private Node mRoot = null;public String toString ( ) {
return toString( mRoot );}//Inorder: Process left subtree// Process data in current node// Process right subtreepublic String toString ( Node n ) {
//base case(s)if (n==null) return “”;//recursive case(s)return toString( n.mLeft ) + “ “ + n.mData + “ “ + toString( n.mRight );
}}
Remaining BST operations
Add a node Remove a node
Add -52 where?
10
5 15
1 7 11 62
40 70
Add -52 where?
10
5 15
1 7 11 62
-52 40 70
Add 6 where?
10
5 15
1 7 11 62
40 70
Add 6 where?
10
5 15
1 7 11 62
6 40 70
Add 13 where?
10
5 15
1 7 11 62
40 70
Add 13 where?
10
5 15
1 7 11 62
13 40 70
Add 43 where?
10
5 15
1 7 11 62
40 70
Add 43 where?
10
5 15
1 7 11 62
40 7043
Add method observations
1. Always add at a leaf node2. (Don’t allow duplicates.)
Algorithm is similar to search/contains.
Recall recursive contains:class MyBST {
private Node mRoot = null;
public boolean containsRecursive ( int value ) {return containsRecursive( value, mRoot );
}
public boolean containsRecursive ( int value, Node n ) {//base case(s)if (n==null) return false; //base caseif (n.mData==value) return true; //base case//recursive case(s)if (value<n.mData) return containsRecursive( value,
n.mLeft );return containsRecursive( value, n.mRight );
}}
Add method (in progress)class MyBST {
private Node mRoot = null;
public void add ( int value ) {if (mRoot==null) mRoot = new Node( value );else add( value, mRoot );
}
public void add ( int value, Node parent ) {…
}}
Add method (in progress)class MyBST {
private Node mRoot = null;
public void add ( int value ) {if (mRoot==null) mRoot = new Node( value );else add( value, mRoot );
}
public void add ( int value, Node parent ) {//base case(s)assert parent!=null; //should never happen!if (value==parent.mData) return; //disallow duplicates…
}}
Completed add methodclass MyBST {
private NodemRoot = null;
public void add ( int value ) {
if (mRoot==null) mRoot = new Node( value );
else add( value, mRoot );
}
public void add ( int value, Node parent ) {
//base case(s)
assert parent!=null; //should never happen!
if (value==parent.mData) return; //disallow duplicates
//possibly recursive case(s)if (value<parent.mData) { if (parent.mLeft==null) parent.mLeft = new Node( value ); else add( value, parent.mLeft );} else { if (parent.mRight==null)parent.mRight = new Node( value ); else add( value, parent.mRight );}
}
Node removal method
Similar to contains and add but more difficult.
Node removal: leaf node example
10
5 15
1 7 11 62
40 70Removal of leaf node is trivial.Now you see it . . .
Node removal: leaf node example
10
5 15
1 7 11 62
40 70Removal of leaf node is trivial.Now you see it . . . now you don’t!
Node removal: interior node example
10
5 15
1 7 11 62
40 70
Removal of interior node is tricky! We can even remove the root!
Remember: only one of 11 or 62 needs to exist for 15 to be an interior node.
Node removal: interior node example
10
5 15
1 7 11 62
40 70
Removal of interior node is tricky! We can even remove the root!
Remember: only one of 11 or 62 needs to exist for 15 to be an interior node.
Node removal: interior node example
10
5 62
1 7 40 70
11
Removal of interior node is tricky! We can even remove the root!
Remember: only one of 11 or 62 needs to exist for 15 to be an interior node.
Node removal: interior node example (alternative)
10
5 15
1 7 11 62
40 70
Removal of interior node is tricky! We can even remove the root!
Remember: only one of 11 or 62 needs to exist for 15 to be an interior node.
Node removal: interior node example (alternative)
10
5 11
1 7 62
40 70
Removal of interior node is tricky! We can even remove the root!
Remember: only one of 11 or 62 needs to exist for 15 to be an interior node.
Node removal (but first, we will need an additional function)
//this function adds node value to subtree parent assuming that// value's data is greater than all data in subtree parentprivate void insertRight ( Node value, Node parent ) {
//precondition(s)assert value !=null; //should never happen!assert parent!=null; //should never happen!assert value.mData>parent.mData; //should never happen!//base and possibly recursive casesif (parent.mRight==null)
parent.mRight = value; //baseelse
insertRight( value, parent.mRight ); //recursive}
Node removalpublic boolean remove ( int value ) {
if (mRoot==null) return false;if (mRoot.mData==value) { //remove root?
//if possible, make left node new root and add right to leftif (mRoot.mLeft!=null) {
insertRight( mRoot.mRight, mRoot.mLeft );mRoot = mRoot.mLeft;
} else if (mRoot.mRight!=null) {mRoot = mRoot.mRight;
} else {mRoot = null;
}return true;
}//not removing the rootif (value<mRoot.mData) return remove( value, mRoot, mRoot.mLeft );else return remove( value, mRoot, mRoot.mRight );
}
Node removal helper methodprivate boolean remove ( int value, Node parent, Node current ) {
if (current==null) return false;if (current.mData==value) {
//if possible, make left node new root and add right to leftif (current.mLeft!=null) {
insertRight( current.mRight, current.mLeft );if (parent.mLeft==current) parent.mLeft = current.mLeft;else parent.mRight = current.mLeft;
} else if (current.mRight!=null) {if (parent.mLeft==current) parent.mLeft = current.mRight;else parent.mRight = current.mRight;
} else {if (parent.mLeft==current) parent.mLeft = null;else parent.mRight = null;
}return true;
}//keep trying to find the node to removeif (value<current.mData) return remove( value, current, current.mLeft );else return remove( value, current, current.mRight );
}
BST efficiency
A BST is very efficient when “balanced.” Balancing is a topic for future classes. What does a BST degrade into when
not balanced? Height of a balanced BST?
Java and trees
Of course, Java already contains an efficient BST implementation called a TreeSet. “This implementation provides
guaranteed log(n) time cost for the basic operations (add, remove and contains).”
See http://java.sun.com/j2se/1.5.0/docs/api/java/util/TreeSet.html
Games and trees (not BSTs)
1. Enumerate possibilities2. Choose best alternative
Games and trees (not BSTs)
Note the arity is sometimes 3, 2, or 5.
Difference between children and siblings.
Games and trees (not BSTs)
Note the arity is sometimes 3, 2, or 5.
Difference between children and siblings.
class Node {int mData;Node mChild;Node mSibling;
}