ch6 Trees
ch6 Trees
Chapter 6
Chapter Objectives
To learn how to use a tree to represent a hierarchical
organization of information
To learn how to use recursion to process trees
To understand the different ways of traversing a tree
To understand the differences between binary trees, binary
search trees, and heaps
To learn how to implement binary trees, binary search trees,
and heaps using linked data structures and arrays
Chapter Objectives (cont.)
To learn how to use a binary search tree to store information so
that it can be retrieved in an efficient manner
To learn how to use a Huffman tree to encode characters using
fewer bytes than ASCII or Unicode, resulting in smaller files
and reduced storage requirements
Trees - Introduction
All previous data organizations we've studied are linear—each
element can have only one predecessor and successor
Accessing all elements in a linear sequence is O(n)
Trees are nonlinear and hierarchical
Tree nodes can have multiple successors (but only one
predecessor)
Trees - Introduction (cont.)
Trees can represent hierarchical organizations of information:
classhierarchy
disk directory and subdirectories
family tree
dog
cat wolf
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
The node at the top
of a tree is called its
root
dog
cat wolf
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
The successors of a
node are called its
children dog
cat wolf
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
dog
The predecessor of a
cat wolf node is called its
parent
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
Each node in a tree
has exactly one parent
except for the root
dog
node, which has no
parent
cat wolf
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
cat wolf
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
dog
cat wolf
cat wolf
dog
canine is a
descendant of cat
in this tree cat wolf
cat wolf
dog
cat wolf
A subtree of a node
canine is a tree whose root
is a child of that
node
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
dog
cat wolf
dog
cat wolf
A subtree of a node
canine is a tree whose root
is a child of that
node
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
dog
The level of a node
is determined by its
cat wolf distance from the
root
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
Level 1 dog
The level of a node
is its distance from
Level 2 cat wolf the root plus 1
Level 3 canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
Level 1 dog
The level of a node
Level 2 is defined
cat wolf
recursively
Level 3 canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
Level 1 dog
The level of a node
Level 2 is defined
cat wolf
recursively
Level 3 canine
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
The height of a
tree is the number
of nodes in the dog
longest path from
the root node to a The height of
leaf node cat wolf this tree is 3
canine
Binary Trees
In a binary tree, each node has two subtrees
A set of nodes T is a binary tree if either of the following is
true
T is empty
Its root node has two subtrees, TL and TR, such that TL and TR are
binary trees
(TL = left subtree; TR = right subtree)
Expression Tree
Each node contains an
operator or an operand
Operands are stored in
leaf nodes
(x + y) * ((a + b) / c)
Parentheses are not stored
in the tree because the tree structure dictates the order of
operand evaluation
Operators in nodes at higher tree levels are evaluated after
operators in nodes at lower tree levels
Huffman Tree
A Huffman tree represents Huffman codes for characters that
might appear in a text file
As opposed to ASCII or Unicode, Huffman code uses different
numbers of bits to encode letters; more common characters use
fewer bits
Many programs that compress files use Huffman codes
Huffman Tree (cont.)
Examples:
d : 10110
e : 010
Binary Search Tree
Binary search trees dog
All elements in the left subtree
precede those in the right subtree cat wolf
A formal definition:
canine
children or 0 children
(the leaf nodes) 2 5 11 13
4 6
Full, Perfect, and Complete Binary Trees
(cont.)
A perfect binary tree
is a full binary tree of 3
2n – 1 nodes
0 2 4 6
In this case, n = 3
and 2n – 1 = 7
Full, Perfect, and Complete Binary Trees
(cont.)
A complete binary
tree is a perfect binary 3
Preorder
Postorder
Tree Traversals
7
Three common kinds
of tree traversal 1 10
Inorder
0 3 9 12
Preorder
Postorder 2 5 11 13
4 6
Tree Traversals (cont.)
Preorder: visit root node, traverse TL, traverse TR
Inorder: traverse TL, visit root node, traverse TR
Postorder: traverse TL, traverse TR, visit root node
Visualizing Tree Traversals
You can visualize a tree
traversal by imagining a
mouse that walks along the
edge of the tree
If the mouse always keeps
the tree to the left, it will
trace a route known as the
Euler tour
The Euler tour is the path
traced in blue in the figure
on the right
Visualizing Tree Traversals (cont.)
A Euler tour (blue path)
is a preorder traversal
The sequence in this
example is
abdgehcfij
The mouse visits each
node before traversing its
subtrees (shown by the
downward pointing
arrows)
Visualizing Tree Traversals (cont.)
If we record a node as the
mouse returns from
traversing its left subtree
(shown by horizontal
black arrows in the
figure) we get an inorder
traversal
The sequence is
dgbheaifjc
Visualizing Tree Traversals (cont.)
If we record each node as
the mouse last encounters
it, we get a postorder
traversal (shown by the
upward pointing arrows)
The sequence is
gdhebijfca
Traversals of Binary Search Trees and
Expression Trees
An inorder traversal of a
binary search tree results dog
import java.io.*;
. . .
}
BinaryTree<E> Class (cont.)
try {
ObjectOutputStream out =
new ObjectOutputStream(new FileOutputStream(filename));
out.writeObject(nameOfObject);
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
A deep copy of all the nodes of the binary tree will be written
to the file
Using ObjectOutputStream and
ObjectInputStream (cont.)
To read a Serializable object from a file:
try {
ObjectInputStream in =
new ObjectInputStream(new FileInputStream(filename));
objectName = (objectClass)in.readObject();
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
Using ObjectOutputStream and
ObjectInputStream (cont.)
Do not recompile the Java source file for a class after an object
of that class has been serialized
Even if you didn't make any changes to the class, the resulting
.class file associated with the serialized object will have a
different class signature
When you attempt to read the object, the class signatures will
not match, and you will get an exception
Constructors
The no-parameter constructor:
public BinaryTree() {
root = null;
}
The constructor that creates a tree with a given node at the root:
this.root = root;
}
Constructors (cont.)
The constructor that builds a tree from a data value and two trees:
public BinaryTree(E data, BinaryTree<E> leftTree,
BinaryTree<E> rightTree) {
a heap
Inserting an Item into a Heap
18 29
20 28 39 66
37 26 76 32 74 89
Inserting an Item into a Heap (cont.)
18 29
20 28 39 66
37 26 76 32 74 89 8
Inserting an Item into a Heap (cont.)
18 29
20 28 39 8
37 26 76 32 74 89 66
Inserting an Item into a Heap (cont.)
18 8
20 28 39 29
37 26 76 32 74 89 66
Inserting an Item into a Heap (cont.)
18 8
20 28 39 29
37 26 76 32 74 89 66
Removing an Item from a Heap
18 8
20 28 39 29
37 26 76 32 74 89 66
Removing an Item from a Heap (cont.)
18 8
20 28 39 29
37 26 76 32 74 89 66
Removing an Item from a Heap (cont.)
66
18 8
20 28 39 29
37 26 76 32 74 89
Removing an Item from a Heap (cont.)
18 66
20 28 39 29
37 26 76 32 74 89
Removing an Item from a Heap (cont.)
18 29
20 28 39 66
37 26 76 32 74 89
Removing an Item from a Heap (cont.)
18 29
20 28 39 66
37 26 76 32 74 89
Implementing a Heap
Because a heap is a complete binary tree, it can be
implemented efficiently using an array rather than a linked
data structure
Implementing a Heap (cont.)
18 29
20 28 39 66
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12
8 18 29 20 28 39 66 37 26 76 32 74 89
Implementing a Heap (cont.)
For a node at position
p,
8
L. child position: 2p
+1
18 29
R. child position: 2p
+2
20 28 39 66
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12
8 18 29 20 28 39 66 37 26 76 32 74 89
Parent
L. Child
R. Child
Implementing a Heap (cont.)
For a node at position
p,
8
L. child position: 2p
+1
18 29
R. child position: 2p
+2
20 28 39 66
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12
8 18 29 20 28 39 66 37 26 76 32 74 89
Parent
L. Child
R. Child
Implementing a Heap (cont.)
For a node at position
p,
8
L. child position: 2p
+1
18 29
R. child position: 2p
+2
20 28 39 66
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12
8 18 29 20 28 39 66 37 26 76 32 74 89
Parent
L. Child
R. Child
Implementing a Heap (cont.)
For a node at position
p,
8
L. child position: 2p
+1
18 29
R. child position: 2p
+2
20 28 39 66
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12
8 18 29 20 28 39 66 37 26 76 32 74 89
Parent
L. Child
R. Child
Implementing a Heap (cont.)
For a node at position
p,
8
L. child position: 2p
+1
18 29
R. child position: 2p
+2
20 28 39 66
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12
8 18 29 20 28
Parent 39 66 37 26 76 32 74 89
L. Child
R. Child
Implementing a Heap (cont.)
18 29 A node at position c
can find its parent
20 28 39 66 at
(c – 1)/2
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12
8 18 29 20 28 39 66 37 26 76 32 74 89
Child
Parent
Inserting into a Heap Implemented as an
ArrayList
20 28 39 66
37 26 76 32 74 89
0 1 2 3 4 5 6 7 8 9 10 11 12 13
8 18 29 20 28 39 66 37 26 76 32 74 89
Inserting into a Heap Implemented as an
ArrayList (cont.)
20 28 39 66
37 26 76 32 74 89 8
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 29 20 28 39 66 37 26 76 32 74 89 8
Child
Inserting into a Heap Implemented as an
ArrayList (cont.)
18 29
20 28 39 66
37 26 76 32 74 89 8
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 29 20 28 39 66 37 26 76 32 74 89 8
Child
Parent
Inserting into a Heap
Implemented as an ArrayList
(cont.)
3. while (parent >= 0
and
6
table[parent] > table[child])
18 29 4. Swap table[parent]
and table[child]
20 28 39 66 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 8
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 29 20 28 39 66 37 26 76 32 74 89 8
Child
Parent
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 29 20 28 39 8 37 26 76 32 74 89 66
Child
Parent
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 29 20 28 39 8 37 26 76 32 74 89 66
Parent
Child
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 29 20 28 39 8 37 26 76 32 74 89 66
Parent
Child
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 29 20 28 39 8 37 26 76 32 74 89 66
Parent
Child
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 8 20 28 39 29 37 26 76 32 74 89 66
Parent
Child
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 8 20 28 39 29 37 26 76 32 74 89 66
Parent
Child
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 8 20 28 39 29 37 26 76 32 74 89 66
Parent
Child
Inserting into a Heap Implemented as an
ArrayList (cont.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
6 18 8 20 28 39 29 37 26 76 32 74 89 66
Removal from a Heap Implemented as
an ArrayList
Removing an Element from a Heap Implemented as an ArrayList
1. Remove the last element (i.e., the one at size() – 1) and set the item at 0 to this value.
2. Set parent to 0.
3. while (true)
4. Set leftChild to (2 * parent) + 1 and rightChild to leftChild + 1.
5. if leftChild >= table.size()
6. Break out of loop.
7. Assume minChild (the smaller child) is leftChild.
8. if rightChild < table.size() and
table[rightChild] < table[leftChild]
9. Set minChild to rightChild.
10. if table[parent] > table[minChild]
11. Swap table[parent] and table[minChild].
12. Set parent to minChild.
else
13. Break out of loop.
Performance of the Heap
remove traces a path from the root to a leaf
insert traces a path from a leaf to the root
This requires at most h steps where h is the height of the tree
The largest full tree of height h has 2h-1 nodes
The smallest complete tree of height h has
2(h-1) nodes
Both insert and remove are O(log n)
Priority Queues
The heap is used to implement a special kind of queue called a
priority queue
The heap is not very useful as an ADT on its own
We will not create a Heap interface or code a class that implements it
Instead, we will incorporate its algorithms when we implement a priority
queue class and heapsort
Sometimes a FIFO queue may not be the best way to implement a
waiting line
A priority queue is a data structure in which only the highest-
priority item is accessible
Priority Queues (cont.)
In a print queue, sometimes it is more appropriate to print a
short document that arrived after a very long document
A priority queue is a data structure in which only the highest-
priority item is accessible (as opposed to the first item entered)
Insertion into a Priority Queue
PriorityQueue Class
Java provides a PriorityQueue<E> class that
implements the Queue<E> interface given in
Chapter 4.
Using a Heap as the Basis of a Priority
Queue
In a priority queue, just like a heap, the smallest item always is
removed first
Because heap insertion and removal is
O(log n), a heap can be the basis of a very efficient
implementation of a priority queue
While the java.util.PriorityQueue uses an Object[] array,
we will use an ArrayList for our custom priority queue,
KWPriorityQueue
Design of a KWPriorityQueue Class
Design of a KWPriorityQueue Class (cont.)
import java.util.*;
// Data Fields
/** The ArrayList to hold the data. */
private ArrayList<E> theData;
/** An optional reference to a Comparator object. */
Comparator<E> comparator = null;
// Methods
// Constructor
public KWPriorityQueue() {
theData = new ArrayList<E>();
}
. . .
offer Method
/** Insert an item into the priority queue.
pre: The ArrayList theData is in heap order.
post: The item is in the priority queue and
theData is in heap order.
@param item The item to be inserted
@throws NullPointerException if the item to be inserted is null.
*/
@Override
public boolean offer(E item) {
// Add the item to the heap.
theData.add(item);
// child is newly inserted item.
int child = theData.size() - 1;
int parent = (child - 1) / 2; // Find child’s parent.
// Reheap
while (parent >= 0 && compare(theData.get(parent),
theData.get(child)) > 0) {
swap(parent, child);
child = parent;
parent = (child - 1) / 2;
}
return true;
}
poll Method
/** Compare two items using either a Comparator object’s compare method
or their natural ordering using method compareTo.
pre: If comparator is null, left and right implement Comparable<E>.
@param left One item
@param right The other item
@return Negative int if left less than right,
0 if left equals right,
positive int if left > right
@throws ClassCastException if items are not Comparable
*/
private int compare(E left, E right) {
if (comparator != null) { // A Comparator is defined.
return comparator.compare(left, right);
} else { // Use left’s compareTo method.
return ((Comparable<E>) left).compareTo(right);
}
}
PrintDocuments Example
Analysis:
Each node will have storage for two data items:
◼ the weight of the node and
◼ the symbol associated with the node
All symbols will be stored in leaf nodes
For nodes that are not leaf nodes, the symbol part has no meaning
The weight of a leaf node will be the frequency of the symbol stored
at that node
The weight of an interior node will be the sum of frequencies of all
leaf nodes in the subtree rooted at the interior node
Building a Custom Huffman Tree (cont.)
Analysis:
A priority queue will be the key data structure in our Huffman tree
We will store individual symbols and subtrees of multiple symbols in
order by their priority (frequency of occurrence)
Building a Custom Huffman Tree (cont.)
Building a Custom Huffman Tree (cont.)
Design