Notes on Homework:
If you have the word "path" in red on your paper, that means you hard-coded a path for i/o. I am not going to chase all over my hard drive looking for output. I/O should always be the path the program runs in. As a result, you lost the 3 points for the Output section of your homework. If you want to modify and re-submit, you will have the opportunity to earn back 2 of the 3 Output points with no further penalty.
A few of you still did not get the Assignment# correct. I have deducted 1 point from your homework grade for this.
Binary Trees
It's easiest to conceptualize a binary tree using a modified version of the doubly linked list. Each node contains:
the key value
the data it is storing
a pointer to its left child
a pointer to its right child
The assignment of pointers changes this from a list to a tree.
Some terminology:
Path: A sequences of edges that connect 2 or more nodes
Root: The node at the top of the tree
Parent: Any node that has an edge running downward, connecting it to another node
Child: Any node that has an edge running upward, connecting it to another node
Leaf: A node with no children
Subtree: A portion of the tree
Visiting: When program control arrives at the node and carries out an operation
Traversing: Visit all nodes in a specified order
Levels: How many "generations" of nodes there are
Keys: The value used to search or perform other operations
Balanced vs Unbalanced Trees
A tree is balanced if it contains approximately the same number of nodes on the left side as it does on the right. When elements are inserted in more or less random order, the tree will be more balanced. If the elements are already ordered, the tree will not be balanced.
Searching the tree
Nodes are inserted into a tree such that the left children are smaller then the parent and the right children are larger than the parent.
The steps to take for finding a value are:
1. Start at the root node.
2. Compare the value to find with the value of the node
3. If the value to find is smaller, and there is a left child, move to the left child and return to step 2.
4. If the value to find is larger, and there is a right child, move to the right child and return to step 2.
5. If the value is equal, you have found it.
6. If there is no appropriate child, then the value is not in the tree
Inserting a Node
Inserting is a matter of first finding the spot to insert it. Follow the search steps outlined above until one of these conditions are met:
1. The value to insert is smaller than the current node, and the node has no left child. The new value will become the new left child of the current node.
2. The value to insert is larger than the current node, and the node has no right child. The new value will become the new right child of the current node.
Traversing the Tree
In-Order Traversal
An in-order traversal causes all nodes to be visited in ascending order.
The recursive steps are as follows:
1. Traverse the node's left subtree
2. Visit the node
3. Travers the node's right subtree
Remember that visiting a node means doing something- diplaying it, writing it to a file, etc. Just because were are at the node doesn't mean that it has been visited.
Note also that we do not visit a node until we have traversed all of the left subtree. This is where the recursion comes in.
The shell for a method would look something like this:
void inOrder(node bTree) {
inOrder(bTree.left);
visit(bTree.value);
inOrder(bTree.right);
}
Pre- and Post-Order Traversals
These traversals have no real meaning unless you are working with algebraic equations.
Let's say you have the following equation loaded into a binary tree:
A * (B + C)
The tree would look something like this:
*
/ \
A +
/ \
B C
A pre-order traversal would generate the equation in prefix notation.
A post-order traversal would generate the equation in postfix notation.
The shell for a pre-order traveral would look something like this:
void preOrder(node bTree) {
visit(bTree.value);
inOrder(bTree.left);
inOrder(bTree.right);
}
The shell for a post-order traveral would look something like this:
void preOrder(node bTree) {
inOrder(bTree.left);
inOrder(bTree.right);
visit(bTree.value);
}
Finding Minimum and Maximum Values
This is a very simple process, given that smaller values are always to the left and larger values to the right.
To find the minimum value, simply move to each successive left child until there are no more. The value in that node will be the minimum.
To find the maximum value, simply move to each successive right child until there are no more. The value in that node will be the maximum.
Deleting a Node
This is a more complicated operation. First, let's define some terms:
current - the node to be deleted
parent - parent of the node to be deleted
right - right child
left - left child
There are three cases to consider:
1. The node has no children
By far, the easiest of the three. Simply set the pointer from the parent to the child to null, then delete the child.
2. The node has one child
This is not too difficult, simply a matter of pointing the node's parent to the node's child. There are four cases to consider:
if the current node has a left child
1. if the current node is the left child of its parent
point the parent left to the current left child
2. else the current node is the right child of its parent
point the parent right to the current left child
else the current node has a right child
3. if the current node is the left child of its parent
point the parent left to the current right child
4. else the current node is the right child of its parent
point the parent right to the current right child
3. The node has two children
This is the most complicated process. As a rule, programmers will include a boolean field in the node to mark it as deleted, rather than go through the gyrations.
First, it is necessary to find the next in-line successor. What this means is: Find the smallest value that is still larger then the value to delete, or the next higher value. This is a simple process, simply move to the right subtree of the node to delete, then follow the left children until you reach the end.
The successor will be one of the following:
Right Child of the Node to Delete
The easiest of the two. To delete the node, change the links as follows:
1. Point the parent right to the successor node
2. Point the successor left to the current left
Left Descendant of Right Child of Node to Delete
To delete the node, change the links as follows:
1. Point the parent left to the successor right
2. Point the successor right to the current right
3. Point the parent right to the successor
4. Point the successor left to the current left
Trees Represented as Arrays
parent- for a node at position x in the array, its parent is located at position (x-1)/2
left child- for a node at position x in the array, its left child is located at 2*x+1, or the right child minus 1
right child- for a node at position x in the array, its right child is located at 2*x+2, or the left child plus 1