Part 1: Task: To find the predecessor of a given key k at a given node* x. Cases to consider: I. x is an internal node. If the given node is not a leaf, the predecessor to the ith key is the largest key of the ith subtree. II. x is a leaf node and k is not the first key. Easy case: then predecessor is simply the previous key. III. x is a leaf node and k is the first key. Harder case: Predecessor is the key in the parent to the left of the pointer to the given node if such a key exists. If there is no such key in parent, then the predecessor is the key in the grandparent to the left of the pointer to the parent node if such a key exists. If no such key exists, we continue searching upward in this fashion until we find such a key. We are guaranteed to eventually find such a key because our assumption is that we are not looking for the predecessor of the minimum. pseudo code: key B_tree_predecessor(node* x, key k1) { find i s.t. k1 == x->K[i]; if (x is an internal node) { return B_tree_max(x->C[i]); } if (x is a leaf node) { if (i > 1) { return x->K[i-1]; } while (true) { x = parent(x); for (i = 1; i <= x->K.size; i++) { if (x->K[i] >= k) { break; } } if (i == 1) { continue; } else { return x->K[i-1]; } } } // end if (x is a leaf node) } // end B_tree_predecessor Grading: part 1 worth 5 points. Handling internal case correctly: worth 2 points. Handling leaf, not 1st key correctly: worth 1 point Handling leaf, 1st key correctly: worth 2 points. Part 2: t=2 so the height h of the n-key B-tree is <= lg((n+1)/2). All nodes except those in the rightmost branch will only have one key. Since we're proving the B-tree has at least a certain # of nodes we can overdeduct and say that every node on the rightmost branch has 3 keys. Then the total # of keys stored in those rightmost nodes = 3 (h+1) = 3h + 3. So the total # of nodes is at least n - 3h - 3 + h+1 = n-2h-2 which gives the desired result. Grading: part 2 worth 3 points. False stmts. lead to deductions of [0,3] depending on the severity and effects on the rest of the proof. Incorrectly drawn figures: -1 Part 3: notation: P(x) means x is nowhere-full Q(x) means x has exactly 2t-2 keys in every node. Let S_h = {trees t: t has height h && P(t)}. Let max_S_h = a maximal element of S_h. TST (To Show That): for every height h, Q(max_S_h). 1. max_S_h exists for every h. By Saunders' argument/observation 2. pick an arbitrary h and pick an arbitrary max_S_h from S_h and call it x. Note that because max_S_h was selected from S_h, we know that P(x). 3. now we have to show that Q(x). Suppose for contradiction !Q(x). 4. There are two cases to consider: Case 1: all the nodes in x that have less than 2t-2 keys are leaves. In this case, just add the non-integer reals to bring their counts up to 2t-2. Call the resulting tree y. Case 2: some of the nodes in x that have less than 2t-2 keys are internal nodes. In this case, you need to add to the leaves under (may not be directly under -- could be a couple of nodes in between) them until the leaves split and propagate keys up to the shy internal nodes until the shy internal nodes are brought up to 2t-2 keys. Then finish the job by bringing the lower nodes up to 2t-2 keys. Call the resulting tree y. 5. Either way, y is in S_h because none of the operations in either of cases 1 or 2 changed the height and P(y). y has more keys than x so x is not a max_S_h. But this is a contradiction with step 2. So we know that our supposition in step 3 must have been false. Hence, Q(x). Grading: part 3 is worth 2 points Handling the leaf case: 1 point Handling the internal case: 1 point A common mistake: proving by giving an example but not proving in general for any height h, minimum degree t Making false statements: [0,2] points depending on severity, etc.