CS 51510 Exam 3 Practice Problems The exam is on Wednesday, December 11, at 10:15 a.m. The exam will be over the following sections. Chapter 10, Section 10.3 from the course textbook. Chapter 12 Binary Search Trees, from the course textbook. Chapter 14 Dynamic Programming, Sections 14.1, 14.3, and 14.4 from the course textbook. Sections 5.1, 5.2, 5.3, and 5.4 from https://people.cs.vt.edu/~shaffer/Book/JAVA3elatest.pdf#page=164 Sections 16.5 and 16.6 from https://bcs.wiley.com/he-bcs/Books?action=mininav&bcsId=3663&itemId=0470105550&assetId=110292&resourceId=10137 Sections 6.2, 6.3, and 6.4 from https://people.eecs.berkeley.edu/~vazirani/algorithms/chap6.pdf Sections 10.1, 10.2, and 10.3 from https://link.springer.com/chapter/10.1007/978-3-030-54256-6_10 The data structures and abstract data types covered are binary tree and binary search tree. The exam also includes dynamic programming. You should be familiar with the example code in http://cs.pnw.edu/~rlkraft/cs51510/for-class/BinaryTree_ADT.zip http://cs.pnw.edu/~rlkraft/cs51510/for-class/BinarySearchTree.zip http://cs.pnw.edu/~rlkraft/cs51510/for-class/dynamic-programming.zip Below are several practice problems that are similar to the kinds of problems that might be on the exam. Problem 1) Here is an outline for the BinaryTree abstract-data-type as an abstract class. Use the first four (abstract) methods in the interface to provide implementations for the other methods in the interface. The preOrder() and toString() methods are done for you as examples. import java.util.List; import java.util.ArrayList; public abstract class BinaryTree { public abstract Integer data(); public abstract BinaryTree left(); public abstract BinaryTree right(); public abstract boolean isEmpty(); public int size() // The number of non-empty nodes in this tree. { } public List preOrder() { final List result = new ArrayList<>(); if (! this.isEmpty()) { result.add( this.data() ); result.addAll( this.left().preOrder() ); result.addAll( this.right().preOrder() ); } return result; } public List inOrder() { } public List postOrder() { } public int sum() // Add up all the elements of this tree. { } @Override public String toString() { return this.isEmpty() ? "()" : (this.left().isEmpty() && this.right().isEmpty())? "" + this.data() : "(" + this.data() + ", " + this.left() + ", " + this.right() + ")"; } } problem 2) Draw a single binary tree T such that Each node of T stores a single character. A pre-order traversal of T yields e,x,a,m,f,u,n. An in-order traversal of T yields m,a,f,x,u,e,n. Problem 3) Give an example of a binary tree, with at least six distinct nodes (no two nodes hold the same value), for which the pre-order traversal of the tree visits the nodes in the same order as the in-order traversal. (This implies that the pre-order and in-order traversals return the same list.) Problem 4) Give an example of two different binary trees T1 and T2, with at least six nodes, such that the pre-order traversal of T1 is the same as the pre-order traversal of T2, and the post-order traversal of T1 is the same as the post-order traversal of T2. Problem 5) Suppose the bst1 and bst2 are each binary search trees. Suppose we use bst1 and bst2 as left and right branches of a new binary tree with a root node n that is greater than the root of bst1 and less than the root of bst2. n / \ / \ bst1 bst2 Show that this new binary tree need not be a binary search tree. Problem 6) Draw a picture of the binary search tree created by this code. BinarySearchTree bst = new BinarySearchTree<>(); bst.add(10); bst.add(1); bst.add(2); bst.add(5); bst.add(11); bst.add(7); bst.add(4); bst.add(9); bst.add(8); bst.add(6); bst.add(3); Problem 7) Write code, similar to the previous problem, that would create the following binary search tree. 10 / \ / \ / \ 7 20 / \ / \ / \ / \ 3 9 14 21 / \ \ \ / \ \ \ 2 6 19 22 Problem 8) Suppose you have a binary search tree with the following shape. Without knowing the values of any of the data elements in this tree, point to (a) the maximum data element of the tree, (b) the minimum data element of the tree, (c) the predecessor element of the root element, (d) the successor element of the root element. # / \ / \ / \ # # / \ / / \ / # # # \ \ \ \ # # Problem 9) This question asks you to compare the following two versions of the remove() method from the BinarySearchTree class. See the complete BinarySearchTree class at http://cs.pnw.edu/~rlkraft/cs51510/for-class/BinarySearchTree.java public boolean removeV1(E data) { if ( ! this.search(data) ) return false; final int comp = data.compareTo(this.data); if (0 > comp) this.left.removeV1(data); else if (0 < comp) this.right.removeV1(data); else { // Remove the root node. if (1 == this.size) { // The root is a leaf. this.data = null; // Create and empty tree. this.left = null; this.right = null; } else if (0 == this.left.size) { this.data = this.right.data; this.left = this.right.left; this.right = this.right.right; } else if (0 == this.right.size) { this.data = this.left.data; this.right = this.left.right; this.left = this.left.left; } else { final E successor = this.right.min(); this.right.removeV1(successor); this.data = successor; } } --this.size; return true; } public boolean removeV2(E data) { if ( ! this.search(data) ) return false; final int comp = data.compareTo(this.data); if (0 > comp) this.left.removeV2(data); else if (0 < comp) this.right.removeV2(data); else { // Remove the root node. if (1 == this.size) { // The root is a leaf. this.data = null; // Create and empty tree. this.left = null; this.right = null; } else if (0 == this.left.size) { final E successor = this.right.min(); this.right.removeV2(successor); this.data = successor; } else { final E predecessor = this.left.max(); this.left.removeV2(predecessor); this.data = predecessor; } } --this.size; return true; } (a) Let bst be the following BinarySearchTree. 4 / \ 3 5 \ 7 / \ 6 8 For each version of the remove() method, draw a picture of the resulting tree after calling the method to remove element 5. (b) Let bst be the following BinarySearchTree. 4 / \ 3 5 \ 9 / \ 6 10 \ 8 / 7 For each version of the remove() method, draw a picture of the resulting tree after calling the method to remove element 5. (c) Describe in words the difference in the behavior between the two versions of the remove method. DO NOT describe the differences in the code. Describe the way in which the two methods act differently. Problem 10) You are searching for the number 363 in a binary search tree containing numbers between 1 and 1000. Which of the following sequences cannot be the sequence of nodes examined? a) 2, 252, 401, 398, 330, 344, 397, 363. b) 924, 220, 911, 244, 898, 258, 362, 363. c) 925, 202, 911, 240, 912, 245, 363. d) 2, 399, 387, 219, 266, 382, 381, 278, 363. e) 935, 278, 347, 621, 299, 392, 358, 363. Problem 11) Let D(i, j) = 1 + D(i, j - 1) + D(i - 2, j) with D(-1, j) = D(0, j) = D(i, 0) = 0. Compute D(6, 6) by filling in the following table in a top-down dynamic programming manner. That is, only fill in those table entries that the top-down algorithm needs filled in to compute D(6, 6). 0 1 2 3 4 5 6 +------+------+------+------+------+------+------+ | | | | | | | | -1 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ | | | | | | | | 0 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ | | | | | | | | 1 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ | | | | | | | | 2 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ | | | | | | | | 3 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ | | | | | | | | 4 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ | | | | | | | | 5 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ | | | | | | | | 6 | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+ Problem 12) Let C(i, j) = C(i - 1, j - 1) + C(i - 2, j - 2) with C(i, 0) = C(0, i) = 0 for 0 <= i <= n and C(i, 1) = C(1, i) = i for 1 <= i <= n. (a) If we implement this as a top-down dynamic programming algorithm, explain why computing C(n, n) is O(n). (b) If we implement this as a bottom-up dynamic programming algorithm, explain why computing C(n, n) is O(n^2). Problem 13) Given an array, A=[a1, a2, ..., an], of n positive numbers, define M(j) = maximum-independent-subsequence-sum between a1 and aj Then M(n) is the maximum-independent-subsequence-sum of A (the largest sum of non-contiguous entries from the array). The recurrence relation for M(j) is given by M(j) = max( aj + M(j-2), M(j-1) ) with M(1) = a1 and M(0) = 0 Suppose that A is the array [6, 7, 5, 4, 5, 5, 3, 6, 3, 4, 3]. (a) Fill in the following bottom-up dynamic programming array M(j) for this MIS problem. 0 1 2 3 4 5 6 7 8 9 10 11 +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | | | | | | | | | | | | | | 0 | 6 | | | | | | | | | | | | | | | | | | | | | | | | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ (b) For the recurrence relation M(j) defined above, explain why the top-down dynamic programming solution to M(j) will never be an improvement over the bottom-up dynamic programming solution. (c) Which entries from the original array make up a maximal independent subsequence? (Don't just list the numbers. Be specific about which entries they are.) Problem 14) In class we solved both the Fibonacci recurrence relation, Fib(0) = 0 Fib(1) = 1 Fib(n) = Fib(n-1) + Fib(n-2) for n >= 2 and the Gibonacci recurrence relation, Gib(0) = 0 Gib(1) = 1 Gib(2) = 1 Gib(3) = 1 Gib(n) = Gib(n-2) + Gib(n-4) for n >= 4 What was the reason for introducing the Gibonacci recurrence relation? What does the Gibonacci recurrence relation demonstrate that the Fibonacci recurrence relation doesn't? Problem 15) Given two arrays, a and b, the longest common subsequence between a, up to index i, and b, up to index j, is computed by the following recurrence relation. / | 0 if i == 0 | 0 if j == 0 | 1 + lcs(a, b, i-1, j-1) if a[i] == b[j] lcs(a, b, i, j) = | / \ | | lcs(a, b, i-1, j) | | max | | if a[i] != b[j] | | lcs(a, b, i, j-1) | \ \ / Let a and b be the following two arrays. int[] a = {1, 2, 3, 4, 5, 6, 7} int[] b = {1, 4, 3, 2, 5, 6, 7} Use the LCS recurrence relation to fill in this top-down (memoization) dynamic programming table. Fill in only those entries in the table needed to compute lcs(a, b, 7, 7). 0 1 2 3 4 5 6 7 +------+------+------+------+------+------+------+------+ | | | | | | | | | 0 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+ | | | | | | | | | 1 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+ | | | | | | | | | 2 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+ | | | | | | | | | 3 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+ | | | | | | | | | 4 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+ | | | | | | | | | 5 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+ | | | | | | | | | 6 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+ | | | | | | | | | 7 | | | | | | | | | | | | | | | | | | +------+------+------+------+------+------+------+------+