Treesnotes From HarvardExtensionSchool
Treesnotes From HarvardExtensionSchool
• In the next few lectures, we’ll look at data structures (trees and
hash tables) that can be used for a more efficient data dictionary.
• We’ll also look at other applications of trees.
What Is a Tree?
root
node
edge
2 3 4 5 6
7 8 9 10 11 12
2 3 4 5 6
7 8 9 10 11 12
13
2 3 4 5 6
7 8 9 10 11 12
13
level 0
level 1
depth = 2 level 2
Binary Trees
• In a binary tree, nodes have at most two children.
• Recursive definition: a binary tree is either:
1) empty, or
2) a node (the root of the tree) that has
• one or more data items
• a left child, which is itself the root of a binary tree
• a right child, which is itself the root of a binary tree
• Example:
26
4 18 38
7 7
null null
• see ~cscie119/examples/trees/LinkedTree.java
4 is the root of 4 18 38
12’s left subtree
7
Preorder Traversal
• preorder traversal of the tree whose root is N:
1) visit the root, N
2) recursively perform a preorder traversal of N’s left subtree
3) recursively perform a preorder traversal of N’s right subtree
5 9
2 6 8
root: 4
print 4
root: 2 root: 2 root: 2 root: 6
print 2 print 6
root: 5 root: 5 root: 5 root: 5 root: 5 root: 5
print 5 ...
root: 7 root: 7 root: 7 root: 7 root: 7 root: 7 root: 7
print 7
time
Postorder Traversal
• postorder traversal of the tree whose root is N:
1) recursively perform a postorder traversal of N’s left subtree
2) recursively perform a postorder traversal of N’s right subtree
3) visit the root, N
5 9
2 6 8
• Note that the root is printed after the two recursive calls.
root: 4
print 4
root: 2 root: 2 root: 2 root: 6
print 2 print 6
root: 5 root: 5 root: 5 root: 5 root: 5 root: 5
...
root: 7 root: 7 root: 7 root: 7 root: 7 root: 7 root: 7
time
Inorder Traversal
• inorder traversal of the tree whose root is N:
1) recursively perform an inorder traversal of N’s left subtree
2) visit the root, N
3) recursively perform an inorder traversal of N’s right subtree
5 9
2 6 8
• Note that the root is printed between the two recursive calls.
Tracing Inorder Traversal
void inorderPrintTree(Node root) {
7
if (root.left != null)
inorderPrintTree(root.left);
System.out.print(root.key + “ ”); 5 9
if (root.right != null)
inorderPrintTree(root.right);
} 2 6 8
root: 4
print 4
root: 2 root: 2 root: 2 root: 6
print 2 print 6
root: 5 root: 5 root: 5 root: 5 root: 5 root: 5
print 5 ...
root: 7 root: 7 root: 7 root: 7 root: 7 root: 7 root: 7
time
Level-Order Traversal
• Visit the nodes one level at a time, from top to bottom
and left to right.
5 9
2 6 8
5 13
3 8 10 18
2 6 15 26
+ /
a * d e
b c
Huffman Encoding
• Huffman encoding is a type of variable-length encoding that is
based on the actual character frequencies in a given document.
• Huffman encoding uses a binary tree:
• to determine the encoding of each character
• to decode an encoded file – i.e., to decompress a
compressed file, putting it back into ASCII
• Example of a Huffman tree (for a text with only six chars):
Leaf nodes are characters.
0 1
Left branches are labeled
with a 0, and right branches
0 1 0 1
are labeled with a 1.
t e If you follow a path from root
0 1 0 1
to leaf, you get the encoding
o i a s of the character in the leaf
example: 101 = ‘i’
Building a Huffman Tree
1) Begin by reading through the text to determine the frequencies.
2) Create a list of nodes that contain (character, frequency) pairs
for each character that appears in the text.
‘o’ ‘i’ ‘a’ ‘s’ ‘t’ ‘e’
21 23 25 26 27 40
‘o’ ‘i’
21 23
5) Repeat steps 3 and 4 until there is only a single node in the list,
which will be the root of the Huffman tree.
Completing the Huffman Tree Example I
• Merge the two remaining nodes with the lowest frequencies:
‘a’ ‘s’ ‘t’ ‘e’ -
25 26 27 40 44
‘o’ ‘i’
21 23
‘t’ ‘e’ - -
27 40 44 51
- - -
44 51 67
- -
67 95
‘t’ ‘e’ - -
27 40 44 51
- -
0 1 0 1
67 95
t e
0 1 0 1
‘t’ ‘e’ - -
27 40 o i a s
44 51
0 1 i 101
0 1
o 100
t e
0 1 s 111
0 1
a s t 00
o i
4) Read through the input file a second time, and write the
Huffman code for each character to the output file.
< 26 12 32 26
12
4 18 38
< 12
7
26
12 32
4 18 38
7
Implementing Binary-Tree Search
public class LinkedTree { // Nodes have keys that are ints
…
private Node root;
public LLList search(int key) {
Node n = searchTree(root, key);
return (n == null ? null : n.data);
}
private static Node searchTree(Node root, int key) {
// write together
}
}
• If we find a node that has the specified key, we return its data
field, which holds a list of the data items for that key.
}
Node newNode = new Node(key, data);
if (parent == null) // the tree was empty
root = newNode;
else if (key < parent.key)
parent.left = newNode;
else
parent.right = newNode;
}
Deleting Items from a Binary Search Tree
• Three cases for deleting a node x
• Case 1: x has no children.
Remove x from the tree by setting its parent’s reference to null.
26 26
ex: delete 4 12 32 12 32
4 18 38 18 38
ex: delete 12 12 32 18 32
18 38 38
26
12 32
4 18 38
7 35
Deleting Items from a Binary Search Tree (cont.)
• Case 3: x has two children (continued):
• replace x with the smallest node in x’s right subtree—
call it y
– y will either be a leaf node or will have one right child. why?
ex:
delete 26
26 x 30 x 30
18 45 18 45 18 45
30 y 30 y 35
35 35
30
// Replace toDelete's key and data
// with those of the replacement item. 35
toDelete.key = replace.key;
toDelete.data = replace.data;
// Recursively delete the replacement
// item's old node. It has at most one
// child, so we don't have to
// worry about infinite recursion.
deleteNode(replace, replaceParent);
} else {
...
}
Balanced Trees
• A tree is balanced if, for each node, the node’s subtrees
have the same height or have heights that differ by 1.
36
38