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