Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
66 views169 pages

ch6 Trees

Uploaded by

Özcan Akay
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
66 views169 pages

ch6 Trees

Uploaded by

Özcan Akay
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 169

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

 Trees are recursive data structures because they can be defined


recursively
 Many methods to process trees are written recursively
Trees - Introduction (cont.)
 This chapter focuses on the binary tree
 In a binary tree each element has two successors
 Binary trees can be represented by arrays and by linked data
structures
 Searching a binary search tree, an ordered tree, is generally
more efficient than searching an ordered list—O(log n) versus
O(n)
Tree Terminology and Applications
Section 6.1
Tree Terminology
A tree consists of a collection of elements or
nodes, with each node linked to its successors

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

The links from a


dog node to its
successors are called
branches
cat wolf

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

Nodes that have the


dog same parent are
siblings

cat wolf

canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors

A node that has no dog


children is called a
leaf node
cat wolf

canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors

Leaf nodes also are


A node that has no dog
known as
children is called a
external nodes,
leaf node
cat wolf and nonleaf nodes
are known as
internal nodes
canine
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors

dog

cat wolf

canine A generalization of the parent-child


relationship is the
ancestor-descendant relationship
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
dog is the parent
of cat in this tree
dog

cat wolf

canine A generalization of the parent-child


relationship is the
ancestor-descendant relationship
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors

cat is the parent dog


of canine in this
tree
cat wolf

canine A generalization of the parent-child


relationship is the
ancestor-descendant relationship
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors

dog
canine is a
descendant of cat
in this tree cat wolf

canine A generalization of the parent-child


relationship is the
ancestor-descendant relationship
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors
dog is an ancestor
of canine in this
tree dog

cat wolf

canine A generalization of the parent-child


relationship is the
ancestor-descendant relationship
Tree Terminology (cont.)
A tree consists of a collection of elements or
nodes, with each node linked to its successors

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

canine A subtree of a node


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

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

• If node n is the root of tree T, its level is 1


• If node n is not the root of tree T, its level is
1 + the level of its parent
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
leaf node cat wolf

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.)

To form a code, traverse the tree from the


root to the chosen character, appending 0
if you branch left, and 1 if you branch
right.
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

A set of nodes T is a binary


search tree if either of the following is true:
 T is empty
 If T is not empty, its root node has two subtrees, TL and TR, such that
TL and TR are binary search trees and the value in the root node of T is
greater than all values in TL and is less than all values in TR
Binary Search Tree (cont.)
 A binary search tree never has to be sorted because its elements
always satisfy the required order relationships
 When new elements are inserted (or removed) properly, the
binary search tree maintains its order
 In contrast, a sorted array must be expanded whenever new
elements are added, and compacted whenever elements are
removed—expanding and contracting are both O(n)
Binary Search Tree (cont.)
 When searching a BST, each probe has the potential to
eliminate half the elements in the tree, so searching can be
O(log n)
 In the worst case, searching is O(n)
Recursive Algorithm for Searching a
Binary Tree
1. if the tree is empty
2. return null (target is not found)
else if the target matches the root node's data
3. return the data stored at the root node
else if the target is less than the root node's data
4. return the result of searching the left subtree of the root
else
5. return the result of searching the right subtree of the root
Full, Perfect, and Complete Binary Trees
7
 A full binary tree is a
binary tree where all 1 10

nodes have either 2 0 3 9 12

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

height n with exactly 1 5

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

tree through level n - 1 5

1 with some extra leaf


0 2 4
nodes at level n (the
tree height), all
toward the left
General Trees
 We do not discuss general trees in this chapter, but nodes of a
general tree can have any number of subtrees
General Trees (cont.)

 A general tree can be


represented using a binary
tree
 The left branch of a node
is the oldest child, and
each right branch is
connected to the next
younger sibling (if any)
Tree Traversals
Section 6.2
Tree Traversals
 Often, we want to determine the nodes of a tree and their
relationship
 We can do this by walking through the tree in a prescribed order
and visiting the nodes as they are encountered
 This process is called tree traversal

 Three common kinds of tree traversal


 Inorder

 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

in the nodes being visited


cat wolf
in sequence by
increasing data value canine

canine, cat, dog, wolf


Traversals of Binary Search Trees and
Expression Trees (cont.)
 An inorder traversal of an *
expression tree results in the + /
sequence
x+y*a+b/c x y + c

 If we insert parentheses where a b


they belong, we get the infix
form:
(x + y) * ((a + b) / c)
Traversals of Binary Search Trees and
Expression Trees (cont.)
 A postorder traversal of an *
expression tree results in the + /
sequence
xy+ab+c/* x y + c

 This is the postfix or reverse a b


polish form of the expression
 Operators follow operands
Traversals of Binary Search Trees and
Expression Trees (cont.)
 A preorder traversal of an *
expression tree results in the + /
sequence
*+xy/+abc x y + c

 This is the prefix or forward a b


polish form of the expression
 Operators precede operands
Implementing a BinaryTree Class
Section 6.3
Node<E> Class

 Just as for a linked list, a


node consists of a data part
and links to successor nodes
 The data part is a reference to
type E
 A binary tree node must have
links to both its left and right
subtrees
Node<E> Class (cont.)
protected static class Node<E>
implements Serializable {
protected E data;
protected Node<E> left;
protected Node<E> right;

public Node(E data) {


this.data = data;
left = null;
right = null;
}
Node<E> is declared as an
public String toString() { inner class within
BinaryTree<E>
return data.toString();
}
}
Node<E> Class (cont.)
protected static class Node<E>
implements Serializable {
protected E data;
protected Node<E> left;
protected Node<E> right;

public Node(E data) {


this.data = data;
left = null;
right = null;
}
Node<E> is declared
public String toString() { protected. This way we
return data.toString(); can use it as a superclass.
}
}
BinaryTree<E> Class (cont.)
BinaryTree<E> Class (cont.)
Assuming the tree is
referenced by variable bT
(type BinaryTree) then . . .
BinaryTree<E> Class (cont.)
bT.root.data references the
Character object storing '*'
BinaryTree<E> Class (cont.)
bT.root.left references the
left subtree of the root
BinaryTree<E> Class (cont.)
bT.root.right references
the right subtree of the
root
BinaryTree<E> Class (cont.)
bT.root.right.data
references the Character
object storing '/'
BinaryTree<E> Class (cont.)
BinaryTree<E> Class (cont.)

 Class heading and data field declarations:

import java.io.*;

public class BinaryTree<E> implements Serializable {


// Insert inner class Node<E> here

protected Node<E> root;

. . .
}
BinaryTree<E> Class (cont.)

 The Serializable interface defines no methods


 It provides a marker for classes that can be written to a binary
file using the ObjectOutputStream and read using the
ObjectInputStream
Using ObjectOutputStream and
ObjectInputStream
 The Java API includes the class ObjectOutputStream that will
write to an external file any object that is declared to be
Serializable
 To declare an object Serializable, add
implements Serializable
to the class declaration
 The Serializable interface contains no methods, but it serves
to mark the class and gives you control over whether or not
you want your object written to an external file
Using ObjectOutputStream and
ObjectInputStream (cont.)
 To write a Serializable object to a file:

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:

protected BinaryTree(Node<E> 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) {

root = new Node<E>(data);


if (leftTree != null) {
root.left = leftTree.root;
} else {
root.left = null;
}
if (rightTree != null) {
root.right = rightTree.root;
} else {
root.right = null;
}
}
getLeftSubtree and getRightSubtree Methods

public BinaryTree<E> getLeftSubtree() {


if (root != null && root.left != null) {
return new BinaryTree<E>(root.left);
} else {
return null;
}
}

 getRightSubtree method is symmetric


isLeaf Method

public boolean isLeaf() {


return (root.left == null && root.right == null);
}
toString Method

 The toString method generates a string representing a preorder


traversal in which each local root is indented a distance
proportional to its depth

public String toString() {


StringBuilder sb = new StringBuilder();
preOrderTraverse(root, 1, sb);
return sb.toString();
}
preOrderTraverse Method
private void preOrderTraverse(Node<E> node, int depth,
StringBuilder sb) {

for (int i = 1; i < depth; i++) {


sb.append(" "); // indentation
}
if (node == null) {
sb.append("null\n");
} else {
sb.append(node.toString());
sb.append("\n");
preOrderTraverse(node.left, depth + 1, sb);
preOrderTraverse(node.right, depth + 1, sb);
}
}
preOrderTraverse Method (cont.)
*
+
x
*
null
null + /
y
null
x y a b
null
/
a (x + y) * (a / b)
null
null
b
null
null
Reading a Binary Tree
 If we use a Scanner to read the individual lines created by the
toString and preOrderTraverse methods, we can
reconstruct the tree

1. Read a line that represents information at the root


2. Remove the leading and trailing spaces using String.trim
3. if it is "null"
4. return null
else
5. recursively read the left child
6. recursively read the right child
7. return a tree consisting of the root and the two
children
Reading a Binary Tree (cont.)

public static BinaryTree<String>


readBinaryTree(Scanner scan) {
String data = scan.next();
if (data.equals("null")) {
return null;
} else {
BinaryTree<String> leftTree = readBinaryTree(scan);
BinaryTree<String> rightTree = readBinaryTree(scan);
return new BinaryTree<String>(data, leftTree,
rightTree);
}
}
Binary Search Trees
Section 6.4
Overview of a Binary Search Tree
 Recall the definition of a binary search tree:
A set of nodes T is a binary search tree if either of the following is
true
◼T is empty
◼ If T is not empty, its root node has two subtrees, TL and TR, such that TL
and TR are binary search trees and the value in the root node of T is
greater than all values in TL and less than all values in TR
Overview of a Binary Search Tree (cont.)
Recursive Algorithm for Searching a
Binary Search Tree
1. if the root is null
2. the item is not in the tree; return null
3. Compare the value of target with root.data
4. if they are equal
5. the target has been found; return the data at the root
else if the target is less than root.data
6. return the result of searching the left subtree
else
7. return the result of searching the right subtree
Searching a Binary Tree

Searching for "kept"


Performance
 Search a tree is generally O(log n)
 If a tree is not very full, performance will be worse
 Searching a tree with only
right subtrees, for example,
is O(n)
Interface SearchTree<E>
BinarySearchTree<E> Class
Implementing find Methods
Insertion into a Binary Search Tree
Implementing the add Methods

/** Starter method add.


pre: The object to insert must implement the
Comparable interface.
@param item The object being inserted
@return true if the object is inserted, false
if the object already exists in the tree
*/
public boolean add(E item) {
root = add(root, item);
return addReturn;
}
 /** Recursive add method.
 post: The data field addReturn is set true if the item is added to
 the tree, false if the item is already in the tree.
 @param localRoot The local root of the subtree
 @param item The object to be inserted
 @return The new local root that now contains the
 inserted item
 */
 private Node<E> add(Node<E> localRoot, E item) {
 if (localRoot == null) {
 addReturn = true;
 return new Node<E>(item);
 } else if (item.compareTo(localRoot.data) == 0) {
 addReturn = false;
 return localRoot;
 } else if (item.compareTo(localRoot.data) < 0) {
 localRoot.left = add(localRoot.left, item);
 return localRoot;
 } else {
 localRoot.right = add(localRoot.right, item);
 return localRoot;
 }
 }
Removal from a Binary Search Tree
 If the item to be removed has no children, simply delete the
reference to the item
 If the item to be removed has only one child, change the
reference to the item so that it references the item’s only child
Removal from a Binary Search Tree
(cont.)
Removing from a Binary Search Tree
(cont.)
 If the item to be removed has two children,
replace it with the largest item in its left
subtree – the inorder predecessor
Removing from a Binary Search Tree
(cont.)
Algorithm for Removing from a Binary
Search Tree
Implementing the delete Method
 Listing 6.5 (BinarySearchTree delete
Methods; pages 325-326)
Method findLargestChild
Testing a Binary Search Tree
 To test a binary search tree, verify that an inorder traversal
will display the tree contents in ascending order after a series of
insertions and deletions are performed
Writing an Index for a Term Paper
 Problem: write an index for a term paper
 The index should show each word in the paper followed by the line
number on which it occurred
 The words should be displayed in alphabetical order

 If a word occurs on multiple lines, the line numbers should be listed


in ascending order:
a, 003
a, 013
are, 003
Writing an Index for a Term Paper
(cont.)
 Analysis
 Store each word and its line number as a string in a tree node
 For example, two occurences of "java": "java, 005" and "java, 010"

 Display the words in ascending order by performing an inorder


traversal
Writing an Index for a Term Paper
(cont.)
 Design
 Use TreeSet<E>, a class based on a binary search tree, provided in
the Java API
 Write a class IndexGenerator with a TreeSet<String> data fields
Writing an Index for a Term Paper
(cont.)
 Listing 6.7 (Class IndexGenerator.java; pages
330-331)
Heaps and Priority Queues
Section 6.5
Heaps and Priority Queues
 A heap is a complete binary tree with the following properties
 The value in the root is
a smallest item in the
tree
 Every nonempty subtree is

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

1. Insert the new element at the


8 end of the ArrayList and set
child to table.size() - 1
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 13
8 18 29 20 28 39 66 37 26 76 32 74 89
Inserting into a Heap Implemented as an
ArrayList (cont.)

1. Insert the new element at the


6 end of the ArrayList and set
child to table.size() - 1
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
Inserting into a Heap Implemented as an
ArrayList (cont.)

2. Set parent to (child – 1)/ 2


6

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 29 4. Swap table[parent]
and table[child]
20 28 39 8 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 29 4. Swap table[parent]
and table[child]
20 28 39 8 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 29 4. Swap table[parent]
and table[child]
20 28 39 8 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 29 4. Swap table[parent]
and table[child]
20 28 39 8 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 8 4. Swap table[parent]
and table[child]
20 28 39 29 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 8 4. Swap table[parent]
and table[child]
20 28 39 29 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 8 4. Swap table[parent]
and table[child]
20 28 39 29 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.)

3. while (parent >= 0


and
6
table[parent] > table[child])
18 8 4. Swap table[parent]
and table[child]
20 28 39 29 5. Set child equal to parent
6. Set parent equal to (child-1)/2
37 26 76 32 74 89 66

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.*;

/** The KWPriorityQueue implements the Queue interface


by building a heap in an ArrayList. The heap is structured
so that the "smallest" item is at the top.
*/
public class KWPriorityQueue<E> extends AbstractQueue<E>
implements Queue<E> {

// 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

/** Remove an item from the priority queue


pre: The ArrayList theData is in heap order.
post: Removed smallest item, theData is in heap order.
@return The item with the smallest priority value or null if empty.
*/
@Override
public E poll() {
if (isEmpty()) {
return null;
}
// Save the top of the heap.
E result = theData.get(0);
// If only one item then remove it.
if (theData.size() == 1) {
theData.remove(0);
return result;
}
// Continues on the next slide
/* Remove the last item from the ArrayList and place it into
the first position. */
theData.set(0, theData.remove(theData.size() - 1));
// The parent starts at the top.
int parent = 0;
while (true) {
int leftChild = 2 * parent + 1;
if (leftChild >= theData.size()) {
break; // Out of heap.
}
int rightChild = leftChild + 1;
int minChild = leftChild; // Assume leftChild is smaller.
// See whether rightChild is smaller.
if (rightChild < theData.size()
&& compare(theData.get(leftChild),
theData.get(rightChild)) > 0) {
minChild = rightChild;
}
// assert: minChild is the index of the smaller child.
// Move smaller child up heap if necessary.
if (compare(theData.get(parent),
theData.get(minChild)) > 0) {
swap(parent, minChild);
parent = minChild;
} else { // Heap property is restored.
break;
}
}
return result;
}
Other Methods
 The iterator and size methods are implemented via
delegation to the corresponding ArrayList methods
 Method isEmpty tests whether the result of calling method
size is 0 and is inherited from class AbstractCollection
 The implementations of methods peek and remove are left as
exercises
Using a Comparator
 To use an ordering that is different from the natural
ordering, provide a constructor that has a
Comparator<E> parameter
/** Creates a heap-based priority queue with the specified initial
capacity that orders its elements according to the specified
comparator.
@param cap The initial capacity for this priority queue
@param comp The comparator used to order this priority queue
@throws IllegalArgumentException if cap is less than 1
*/
public KWPriorityQueue(int cap, Comparator<E> comp) {
if (cap < 1)
throw new IllegalArgumentException();
theData = new ArrayList<E>();
comparator = comp;
}
compare Method

 If data field comparator references a Comparator<E> object,


method compare delegates the task to the object’s compare
method
 If comparator is null, it will delegate to method compareTo
compare Method (cont.)

/** 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

 The class PrintDocument is used to define documents to be


printed on a printer
 We want to order documents by a value that is a function of
both size and time submitted
 In the client program, use
Queue printQueue =
new PriorityQueue(new ComparePrintDocuments());
PrintDocuments Example (cont.)
Huffman Trees
Section 6.6
Huffman Trees
 A Huffman tree can be implemented using a binary tree and a
PriorityQueue
 A straight binary encoding of an alphabet assigns a unique
binary number to each symbol in the alphabet
 Unicode is an example of such a coding
 The message “go eagles” requires 144 bits in Unicode but only
38 bits using Huffman coding
Huffman Trees (cont.)
Huffman Trees (cont.)
Building a Custom Huffman Tree
 Suppose we want to build a custom Huffman tree for a file
 Input: an array of objects such that each object contains a
reference to a symbol occurring in that file and the frequency of
occurrence (weight) for the symbol in that file
Building a Custom Huffman Tree (cont.)

 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

Algorithm for Building a Huffman Tree


1. Construct a set of trees with root nodes that contain each of the individual
symbols and their weights.
2. Place the set of trees into a priority queue.
3. while the priority queue has more than one item
4. Remove the two trees with the smallest weights.
5. Combine them into a new binary tree in which the weight of the tree
root is the sum of the weights of its children.
6. Insert the newly created tree back into the priority queue.
Design (cont.)
Implementation
 Listing 6.9 (Class HuffmanTree; page 349)
 Listing 6.10 (The buildTree Method (HuffmanTree.java);
pages 350-351)
 Listing 6.11 (The decode Method (HuffmanTree.java); page
352)

You might also like