Answers to Selected Exercises Chapter 1 Many of the questions in this chapter's exercise are "thought questions." The answers given here are typical or suggested responses, but are not the only possible answers. 1. 4. 7. 10. 14. 17. 20. 23. Software engineering is a disciplined approach to the creation and maintenance of computer programs throughout their whole life cycle. Some software tools used in developing computer programs are text editors, compilers, assemblers, operating systems, and debugging programs. Goal 4 says, "Quality software is completed on time and within budget." (a) When a student does not complete a programming assignment on time, it usually hurts his or her grade. Also, some concepts that were to be learned in preparation for the next programming assignment may not be mastered in time to be put into practice. (b) When a team developing a highly competitive new software product does not complete its work on time, the company must continue to pay salaries, office rent, etc., increasing the "development cost" of the product. The product may go on the market late, after competing products have been released, hurting its sales. This may have an effect on the team members' professional evaluations (like a student's grade). An object is an individual while a class is a description of a group of objects with similar properties and behaviors. Labrador dogs is an example of a class and Maggie is an example of an object. An expert understanding of your programming language saves you time and debugging because (a) you can avoid syntax errors, (b) you can more quickly identify and correct those syntax errors that occur, and (c) you can avoid errors caused by a misunderstanding of the way the language works. The body of the While loop is not in brackets. The comments include the call to Increment. The parameter to Increment is not a reference parameter. Unit testing is the testing of a single unit of the program (for instance, a function). Integration testing is the testing of groups of already tested units to make sure that they interact correctly and that the whole program works according to its specification. (a) The functional domain consists of the whole numbers from 0 to 100. (b) It is possible to carry out exhaustive data coverage for this program. (c) Devise a test plan for this program. Input: All values from 1 to 100. Expected Output: For input 0-59 F For input 60-69 D For input 70-79 C For input 80-89 B For input 90-100 A 26. Life-cycle verification refers to the idea that program verification activities can be performed throughout the program's life cycle, not just by testing the program after it is coded. 29. (a) num and denom are both just integer values. Each can be either negative or positive. In a fraction the numerator carries the sign. The denominator should always be positive. (b) IsNotProper needs to be changed to use the absolute value of the numerator. Function Initialize (or any constructor) should check to be sure the denominator is strictly positive and throw an exception if this is not the case. (c) The following tests need to be added to the test plan. Operation to Be Tested and Description of Input Expected Output Action Values Initialize -3,4 Numerator: -3 Denominator: 4 IsNotProper Initialize Fraction is proper -13,4 Numerator: -13 Denominator: 4 IsNotProper Fraction is improper ConvertToProper Whole number is 3 Numerator is -1 Denominator is 4 Chapter 2 2. Data encapsulation is the separation of the physical representation of data from the applications that use the data at a logical (abstract) level. When data abstraction is protected through encapsulation, the data user can deal with the data abstraction but cannot access its implementation, which is encapsulated. The data user accesses data that is encapsulated through a set of operations specified to create, access, and change the data. Data encapsulation is accomplished through a programming language feature. 5. array, struct, union, and classes 8. The syntax of the component selector is the array name followed by the index of the desired item: array-name[index-expression] 11. (a) typedef WeatherType WeatherListType[12]; WeatherListType yearlyWeather; (b) yearlyWeather[6].actualRain = 1.05; (c) 238 14. Member-length-offset table for StudentRecord. Field Length Offset firstName 10 0 lastName 10 10 id 1 20 gpa 2 21 currentHours 1 23 totalHours 1 24 17. (a) A square two-dimensional array (b) struct or class (c) struct or class containing two data members: the number of quotations and an array of strings that holds them (d)a one-dimensional integer array (e) a two-dimensional integer array (f) a three-dimensional integer array (g) an array of structs or classes (h) a one-dimensional integer array 20. The members of a class are private unless specified as public. Client code cannot access private members. 23. Classes can relate to one another through inheritance, containment (composition), and not at all. 28. (a) SquareMatrix ADT Specification Structure: An NxN square integer matrix. Operations : MakeEmpty(int n) Function: Initializes the size of the matrix to n and sets the values to zero. Precondition: n is less than or equal to 10. Postconditions: Matrix contains all zero values. StoreValue(int i, int j, int value) Function: Stores value into the i,jth position in the matrix. Preconditions Matrix has been initialized; i and j are between 0 and the size minus 1. Postconditions: value has been stored into the i,jth position of the matrix. Add(SquareMatrixType one, SquareMatrixType two, SquareMatrixType result) Function: Adds matrix one and matrix two and stores the result in result. Precondition: one and two have been initialized and are the same size. Postcondition: result = one + two. Subtract(SquareMatrixType one, SquareMatrixType two, SquareMatrixType result) Function: Subtracts two from one and stores the result in result. Precondition: one and two have been initialized and are the same size. Postcondition: result = one - two. Print(SquareMatrixType one) Function: Prints the matrix on the screen. Precondition: Matrix has been initialized. Postcondition: The values in the matrix have been printed by row on the screen. Copy(SquareMatrixType one, SquareMatrixType two) Function: Copies two into one. Precondition: two has been initialized. Postcondition: one = two. (b) The following declaration contains only additional pre/post conditions required by the implementation. class SquareMatrixType { public: void MakeEmpty(int n); // Pre: n is less than or equal to 50. // Post: n has been stored into size. void StoreValue(int i, int j, int value); // Pre: i and j are less than or equal to size. void Add(SquareMatrixType two, SquareMatrixType result); // Post: result = self + two. void Subtract(SquareMatrixType two, SquareMatrixType result); // Post: result = self - two. void Print(); // Post: The values in self have been printed by row on the screen. void Copy(SquareMatrixType two); // Post: self = two private: int size; // Dimension of the matrix. int matrix[10][10]; }; (c) void SquareMatrixType::MakeEmpty(int n) { size = n; for (int row = 0; row < size; row++) for (int col = 0; col < size; col++) matrix[row][col] = 0; } void SquareMatrixType::StoreValue(int i, int j, int value) { matrix[i][i] = value; } void SquareMatrixType::Add(SquareMatrixType two, SquareMatrixType result) { for (int row = 0; row < size; row++) for (int col = 0; col < size; col++) result.matrix[row][col] = matrix[row][col] + two.matrix[row][col]; } void SquareMatrixType::Subtract(SquareMatrixType two, SquareMatrixType result) { for (int row = 0; row < size; row++) for (int col = 0; col < size; col++) result.matrix[row][col] = matrix[row][col] two.matrix[row][col]; } void SquareMatrixType::Print() { for (int row = 0; row < size; row++) for (int col = 0; col < size; col++) cout << matrix[row][col]; } void SquareMatrixType::Copy(SquareMatrixType two) { for (int row = 0; row < size; row++) for (int col = 0; col < size; col++) matrix[row][col] = two.matrix[row][col]; } (d) This test plan is a black box strategy with data values representing the end cases and a general case. For matrix operations, the end cases represent the size of the matrices, not the values stored in them. We assume that integer addition and subtraction are correct. Operation to be Tested and Description of Action Input Expected Values Output MakeEmpty 2 0 0 execute and print 0 0 0 no output execute and print 50 50x50 matrix execute and print of zeros StoreValue MakeEmpty(2) 1,1,2 store 1,2,3 store 2,2,4 store 2 3 print 0 4 Add General Case 1 2 Create a second matrix 3 4 3 5 Add to first one created and print 3 8 End Case (size 0) no output Add two empty matrices and print End Case (size 50) Create a 50x50 matrix of ones Create a 50x50 matrix of twos 50x50 of threes Add and print Subtract General Case Subtract the first from the second and print End Case (size 0) Subtract two size 0 matrices and print End Case (size 50) Subtract all ones from all twos Copy Copy first and print Copy a size 0 matrix and print Copy a size 50 matrix of twos and print -1 -1 3 0 no output 50x50 of ones 2 3 0 4 no output 50x50 of twos 31. If functions GetMonthAsString and Adjust are called frequently, then the first version is more efficient because access to the string or number of days would be O(1). On the other hand, if these functions are called only once, it would be better to calculate these values and store them. The second alternative would require two new class variables, one to hold the string and one to hold the number of days, but the auxiliary arrays would no longer be need. Chapter 3 1. (a) Boolean IsThere(ItemType item) Function: Determines if item is in the list. Precondition: List has been initialized. Postcondition: Function value = there exist an item in the list whose key is the same as item's. (b) bool IsThere(ItemType item) const; (d) O(N) where N is the number of items in the list. 5. (a) DeleteItem (ItemType item ) Function: Deletes the element whose key matches item's key. Preconditions: List has been initialized. Key member of item is initialized. At most one element in list has a key matching item's key. Postcondition: If an element in list had a key matching item's key, the item has been removed; otherwise, the list is unchanged. (c) DeleteItem (ItemType item ) Function: Deletes the element whose key matches item's key. Preconditions: List has been initialized. Key member of item is initialized. Postcondition: No element in list has a key matching item's key. 8. (a) True (b) True (c) False. A linked list is not a random-access structure. (d) False. A sequential list may be stored in a statically allocated or a dynamically allocated structure. (e) True (f) False. A queue is not a random-access structure; access is always to the first one stored. 10. (a) true (b) false (c) false (d) true 12. (a) listData = ptr1->next; (b) ptr2 = ptr2->next; (c) listData = NULL (d) ptr1->next->info = 60 Answers for the table: Statements Memory allocated int value; value = 500; char* charPtr; char string[10] = "Good luck"; charPtr = string; cout << &value; // question cout << value; // question cout << &charPtr; // question cout << charPtr; // question What is printed? value is assigned to location 200 charPtr is at location 202 string[0] is at location 300 19 20 21 22 & means "the address of" & means "the address of" 200 500 202 Good l u c k cout << *charPtr; // question 23 cout << string[2]; // question 24 G o 16. None of the changes in Exercises 9 and 10 change the Big-O from that discussed in the chapter. Each of the delete operations still have order O(N). Chapter 4 1. (a) Boolean IsThere(ItemType item) Function: Determines if item is in the list. Precondition: List has been initialized. Postcondition: Function value = there exist an item in the list whose key is the same as item's. (b) bool IsThere(ItemType item) const; (c) bool SortedType::IsThere(ItemType item) { int midPoint; int first = 0; int last = length - 1; bool moreToSearch = first <= last; bool found = false; while (moreToSearch && !found) { midPoint = (first + last) / 2; switch (item.ComparedTo(info[midPoint]) { case LESS : last = midPoint - 1; moreToSearch = first <= last; break; case GREATER : first = midPoint + 1; moreToSearch = first <= last; break; case EQUAL : found = true; break; } } return found; } (d) O(log2N) where N is the number of items in the list. 3. (a) Boolean IsThere(ItemType item, UnsortedType list) Function: Determines if item is in the list. Precondition: list has been initialized. Postcondition: Function value = there exist an item in the list whose key is the same as item's. (b) bool IsThere(SortedType list, ItemType item) { int length; bool found = false; int counter = 1; ItemType listItem; length = list.LengthIs(); list.ResetList(); while (!found && counter <= length) { list.GetNextItem(listItem); if (listItem.ComparedTo(item) == EQUAL) found = true; counter++; } return found; } or bool IsThere(SortedType list, ItemType item) { bool found; list.RetrieveItem(item, found); return found; } (c) The client code does not have access to the array containing the data values, so the binary search algorithm could not be used. (d) The version that iterates through the items is O(N); the version that uses RetrieveItem would have the same complexity as RetrieveItem. (e) The member function has access to the array holding the values, so the binary search algorithm can be used. Therefore, the complexity if O(log 2N) rather O(N). 4. (a) void MergeLists(SortedType list1, SortedType list2, SortedType& result); (b) void MergeLists(SortedType list1, SortedType list2, SortedType& result) { int length1; int length2; int counter1 = 1; int counter2 = 1; ItemType item1; ItemType item2; length1 = list1.LengthIs(); length2 = list2.LengthIs(); list1.ResetList(); list2.ResetList(); list1.GetNextItem(item1); list2.GetNextItem(item2); result.MakeEmpty(); while (counter1 <= length1 && counter2 <= length2) switch (item1.ComparedTo(item2)) { case LESS : result.InsertItem(item1); if (counter1 < length1) list1.GetNextItem(item1); counter1++; break; case GREATER: result.InsertItem(item2); if (counter2 < length2) list2.GetNextItem(item2); counter2++; break; } for (; counter1 <= length1; counter1++) { result.InsertItem(item1); if (counter1 < length1) list1.GetNextItem(item1); } for (; counter2 <= length2; counter2++) { result.InsertItem(item2); if (counter2 < length2) list2.GetNextItem(item2); } } (c) Because the lists that are being merged are sorted, the complexity is O(N) times the complexity of the InsertItem operation. Chapter 5 1. 3. 5. 8. (a) Yes (b) No (c) Yes (d) No (e) Yes (f) No (g) No (h) Yes (a) 3 5 4 (on one line) 5 16 1 0 (each on a separate line) (b) 0 5 6 5 (each on a separate line) 5 4 0 (on one line) stack.Push(letter); letter X letter X stack.top 4 stack.top 4 .overFlow .overFlow T .underFlow .underFlow .items A B C D E .items A B C D E [0 [1 [2 [3 [4 [0 [1 [2 [3 [4 ] ] ] ] ] ] ] (a) Set secondElement to the second element in the stack, leaving the stack without its original top two elements. { stack.Pop(secondElement); stack.Pop(secondElement); } (b) Set bottom equal to the bottom element in the stack, leaving the stack empty. { while (!stack.IsEmpty()) stack.Pop(bottom); } (c) Set bottom equal to the bottom element in the stack, leaving the stack unchanged. { StackType tempStack; ItemType tempItem; while (!stack.IsEmpty()) { stack.Pop(tempItem); tempStack.Push(tempItem); } bottom = tempItem; // restore stack while (!tempStack.IsEmpty()) { ] ] tempStack.Pop(tempItem); stack.Push(tempItem); } } (d) Make a copy of the stack, leaving the stack unchanged. { StackType tempStack; ItemType tempItem; while (!stack.IsEmpty()) { stack.Pop(tempItem); tempStack.Push(tempItem); } // restore stack while (!stack.IsEmpty()) { tempStack.Pop(tempItem); stack.Push(tempItem); copy.Push(tempItem) } } 12. (a) Draw a diagram of how the stack might look. smallTop: top for the stack of small values, initialized to -1 and incremented. largeTop: top for the stack of large values, initialized to 200 and decremented. [0] [1] [2] [3] (b) class DStack { public: DStack(); void Push(int item); void PopLarge(int& item); void PopSmall(int& item); private: int smallTop; int largeTop; int items[200]; } (c) void Push(int item) { if (item <= 1000) { small++; items[small] = item; } else { large--; items[large] = item; } } 15. .... [197] [198] [199] void (StackType& stack, ItemType oldItem, ItemType newItem) { StackType tempStack; ItemType tempItem; while (!stack.IsEmpty()) { stack.Pop(tempItem); if (tempItem.ComparedTo(oldItem) == EQUAL) tempStack.Push(newItem); else tempStack.Push(tempItem); } // restore stack while (!stack.IsEmpty()) { tempStack.Pop(tempItem); stack.Push(tempItem); } } 17. Stack ADT Specification Structure: Elements are added to and removed from the top of the stack. Definitions (provided by user): MAX_ITEMS: Maximum number of items that might be on the stack. ItemType: Data type of the items on the stack. Operations (provided by the ADT): MakeEmpty Function: Sets stack to an empty state. Precondition: None Postcondition: Stack is empty. Boolean IsEmpty Function: Determines whether the stack is empty. Precondition: Stack has been initialized. Postcondition: Function value = (stack is empty) Boolean IsFull Function: Precondition: Postcondition: Determines whether the stack is full. Stack has been initialized. Function value = (stack is full) Push(ItemType newItem, Boolean& error) Function: Adds newItem to the top of the stack. Precondition: Stack has been initialized. Postcondition: If stack is not full, newItem is at the top of the stack and error is false; otherwise, error is true and the stack is unchanged. Pop(ItemType& item, Boolean& error) Function: Removes top item from Stack and returns it in item. Preconditions: Stack has been initialized and is not empty. Postcondition: If the stack is not empty, the top element has been removed from stack, item is a copy of removed item, and error is false; otherwise, error is true and the stack is unchanged. (b) None (c) None An alternative implementation would add an error data member to the class. This error flag would be set if underflow or overflow occurred and the operation would not be performed. A member function would have to be added to the class to allow the user to check the error flag. 20. Yes, this sequence is possible. 22. (a) 1 0 4 5 16 0 3 (b) 6 4 6 0 6 5 5 24. queue.Enqueue(letter); letter J letter J queue.front .rear .overFlow .underFlow .items 4 3 queue.front .rear .overFlow .underFlow .items 4 3 T V W X Y Z [0 [1 [2 [3 [4 ] ] 27. queue.Dequeue(letter); letter queue.front .rear .overFlow .underFlow .items 4 2 V W X Y Z [0 [1 [2 [3 [4 ] ] ] ] ] V W X Y Z [0 [1 [2 [3 [4 ] ] letter V queue.front .rear .overFlow .underFlow .items 0 2 ] ] ] F V W X Y Z [0 [1 [2 [3 [4 ] ] 30. (a) Set secondElement to the second element in the queue, leaving the queue without its original front two elements. { queue.Dequeue(secondElement); queue.Dequeue(secondElement); } (b) Set last equal to the rear element in the queue, leaving the queue empty. { while (!queue.IsEmpty()) queue.Dequeue(last); } (c) Set last equal to the rear element in the queue, leaving the queue unchanged. { ] ] ] ] QueType tempQ; ItemType item; while (!queue.IsEmpty()) { queue.Dequeue(last); tempQ.Enqueue(last); } while (!tempQ.IsEmpty()) { tempQ.Dequeue(item); ueue.Enqueue(item); } } (d) A copy of the queue, leaving the queue unchanged. { QueType<ItemType> tempQ; ItemType item; while (!queue.IsEmpty()) { queue.Dequeue(item); tempQ.Enqueue(item); } while (!tempQ.IsEmpty()) { tempQ.Dequeue(item); queue.Enqueue(item); copy.Enqueue(item); } } 32. The correct answer for the first statement is (d); the correct answer for the second statement is (a). 35. (a) No (b) Yes (c) No (d) No (e) Yes (f) Yes (g) No (h) Yes (i) No 37. int Length(QueType<ItemType> queue) { QueType<ItemType> tempQ; ItemType item; int length = 0; while (!queue.IsEmpty()) { queue.Dequeue(item); tempQ.Enqueue(item); } while (!tempQ.IsEmpty()) { tempQ.Dequeue(item); queue.Enqueue(item); length++; } return length; } 39. The second else-clause is only executed if both queues are not empty, but one had to be empty for the loop to be exited, so only one can be empty. Therefore, string1 can only be assigned a value from one queue or the other but not both. 42. No, this sequence is not possible. 44. #include "StackType.h" #include <iostream> bool IsOpen(char symbol); bool IsClosed(char symbol); bool Matches(char symbol, char openSymbol); int main() { using namespace std; char symbol; StackType stack; bool balanced = true; char openSymbol; try { cout << "Enter an expression and press return." << endl; cin.get(symbol); while (symbol != '\n' && balanced) { if (IsOpen(symbol)) stack.Push(symbol); else if (IsClosed(symbol)) { if (stack.IsEmpty()) balanced = false; else { openSymbol = stack.Top(); stack.Pop(); balanced = Matches(symbol, openSymbol); } } cin.get(symbol); } } catch (FullStack error) { cout << "Push called when the stack is full." << endl; return 1; } catch (EmptyStack error) { cout << "Top or Pop called when stack is empty." << endl; return 1; } if (balanced) cout << "Expression is well formed." << endl; else cout << "Expression is not well formed." << endl; return 0; } bool IsOpen(char symbol) { if ((symbol == '(') || (symbol == '{') || (symbol == '[')) return true; else return false; } bool IsClosed(char symbol) { if ((symbol == ')') || (symbol == '}') || (symbol == ']')) return true; else return false; } bool Matches(char symbol, char openSymbol) { return (((openSymbol == '(') && symbol == ')') || ((openSymbol == '{') && symbol == '}') || ((openSymbol == '[') && symbol == ']')); } Chapter 6 3. 6. Member functions Enqueue and Dequeue would have to be changed. No, the class definition would not have to be changed. Only the definition of NodeType would have to be changed. 9. Write a member function Copy of the Stack ADT, assuming that self is copied into the stack named in the parameter list. template <class ItemType> void StackType<ItemType>::Copy(StackType<ItemType>& anotherStack) { NodeType<ItemType>* ptr1; NodeType<ItemType>* ptr2; if (topPtr == NULL) anotherStack.topPtr = NULL; else { anotherStack.topPtr = new NodeType<ItemType>; anotherStack.topPtr->info = topPtr->info; ptr1 = topPtr->next; ptr2 = anotherStack.topPtr; while (ptr1 != NULL) { ptr2->next = new NodeType<ItemType>; ptr2 = ptr2->next; ptr2->info = ptr1->info; ptr1 = ptr1->next; } ptr2->next = NULL; } } 12. (a) Doubly linked (b) Circular (c) List with header and trailer 15. (b) 17 4 25 (c) free list nodes 3 1 .info 17 4 25 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] .next 2 0 NUL .back 1 NUL 0 .next 3 2 NUL .back (d) free list nodes [0] [1] [2] [3] [4] [5] [6] [7] 0 1 .info 17 4 25 1 NUL 1 [8] [9] 17. Static binding is the determination of which function to call at compile time; dynamic binding is the determination of which function to call at run tim Chapter 7 1. (a) The base case is a nonrecursive exit from the recursive routine. (b) The general (or recursive) case is a path that includes a recursive call to the routine, to solve a smaller version of the original problem. (c) The run-time stack is a structure that keeps track of the activation records at run time, in order to preserve the values of parameters, return addresses, registers, and so on. (d) Binding time refers to the point in the compile/execution cycle when variable names are associated with addresses in memory. (e) Tail recursion occurs when the recursive call is the last statement executed in a recursive function. 4. Answering yes to Question 1 provides us with a base case that works correctly. In answering Question 3, we make an assumption that the function works for some artibary case. We can then show that applying the function to the next value results in the correct answer in the general case. 7. (a) The base cases are return -1 and return 1. (b) The general case is return base*Puzzle(base+1, limit). 10. (a) int Power(int base, int exponent) // Returns the base raised to the exponent { if (exponent == 0) return 1; // base case else return base * Power(base, exponent-1); // general case } (b) int Factorial(int number) // Returns the factorial of number (number!) { if (num > 0) return num * Factorial(num - 1); // general case else if (num == 0) return 1; // base case } (c) void Sort(int values[], int fromIndex, int toIndex) // Sorts values from values[fromIndex] .. values[toIndex]. // The maximum value left in the unsorted portion is put into its // proper place on each call. { int maxIndex; if (fromIndex != toIndex) { // general case maxIndex = MaxPosition(values, fromIndex, toIndex); Swap(values[maxIndex], values[toIndex]); Sort(values, fromIndex, toIndex - 1); } // base case is when fromIndex equals toIndex: do nothing } 13. (a) int Fibonacci(int number) { if (number <= 1) return number; else return Fibonacci(number - 2) + Fibonacci(number - 1); } (b) int Fibonacci(int number) { int current; int previous; int temp; if (number <= 1) return 1; else { previous = 0; current = 1; for (int count = 2; count <= number; count++) { temp = previous; previous = current; current = temp + previous; } return current; } } (c) #include <iostream> int Fibonacci(int number); int main() { using namespace std; int number; cout << "Input the fibonacci number you wish." << endl; << "Input a negative number to quit." << endl; cin >> number; while (number >= 0) { cout << "number: " << number << endl; << "Fibonacci number: " << Fibonacci(number) << endl; cout << "Input the fibonacci number you wish." << endl; << "Input a negative number to quit." << endl; cin >> number; } return 0; } // Put the function version you are testing here. (d) The recursive solution is inefficient because some of the intermediate values are calculated more than once. (e) The following version, which uses an auxiliary recursive function, is more efficient. Note that the recursive parameters are used to keep track of the current and previous numbers, rather than recalculating them. int Fibonacci(int number) { return Fib(number, 1, 1); } int Fib(int number, int previous, int current) { if (number == 0) return previous; else return Fib(number - 1, current, current + previous) } 16. (a) // corrected version int NumPaths(int row, int col, int n) { if (row == n || col == n) return 1 else return NumPaths(row + 1, col, n) + NumPaths(row, col + 1, n); }. (b) The algorithm is inefficient because it calculates some of the intermediate values of NumPaths more than once. (c) const int MAX = 10; int table[MAX][MAX]; . . . int NumPaths2(int row, int col, int n) { if (row == n || col == n) table[row][col] = 1; else if (table[row][col] == 0) table[row][col] = NumPaths2(row+1, col, n) + NumPaths2(row, col+1, n) return table[row][col]; } (d) // initialize table for (int i = 0; i < MAX; i++) for (int j = 0; j < MAX, j++) table[i][j] = 0; // solve problem answer = NumPaths2(l, l, MAX); (e) The second version is more efficent in terms of execution time, but requires additional space for an N x N array of integers. 19. Binding time refers to the point in the compile/execute cycle when variable names are associated with addresses in memory. For recursion to be possible, parameters must be bound to addresses at run time, not at compile time. 22. (a) False. Recursive solutions are often less efficient in terms of computing time. (b) True (c) False. Recursive solutions generally require more space in the run-time stack. (d) True. (Don't you want a good grade in this course?) Chapter 8 2. 5. 10. 13. 14. 17. 19. (c) is the correct answer (a) 30 (5 different shapes with 6 different combinations of values for each) (b) 5 (5 different shapes with one legal combinations of values for each) Show what order the nodes in the tree are processed by (a) BDJKMNPQRTWY (b) BJDNPMKRWYTQ (c) QKDBJMPNTRYW (a) The path would go through the nodes containing 56, 69, 59, 62, and 61. (b) The path would go through the nodes containing 56, 47, 22, 29, and 23, before determining that 28 is not in the tree. (a) 11 22 23 29 30 47 49 56 59 61 62 64 69 (b) 11 23 30 29 22 49 47 61 64 62 59 69 56 (c) 56 47 22 11 29 23 30 49 69 59 62 61 64 (a) False (b) False (c) True (d) False (a) Elements inserted in random order: Linked list: O(N) Binary search tree: O(log2N) (b) Elements inserted in order: Linked list: O(N) Binary search tree: O(N) 22 template<class ItemType> void DeleteNode(TreeNode<ItemType>*& tree) // Deletes the node pointed to by tree. // Post: The user's data in the node pointed to by tree is no // longer in the tree. If tree is a leaf node or has one NULL // child pointer // the node pointed to by tree is deleted; otherwise, the // user's data is replaced by its logical successor and the // successor's node is deleted. { TreeNode<ItemType>* tempPtr; ItemType data; tempPtr = tree; if (tree->left == NULL) tree = tree->right; else if (tree->right == NULL) tree = tree->left; else { tempPtr = PtrToSuccessor(tree); tree->info = tempPtr->data; } delete tempPtr; } 24. 1. The Base-Case Question: Yes. The base case occurs when the node to be deleted has been found, when item equals tree->info. In this case we call the DeleteNode function; no further recursive calls are made. 2. The Smaller-Caller Question: Yes. In each of the two general cases, a recursive call is made to delete the element from a subtree, left or right, of the current tree. Deleting from a subtree is a smaller version of the problem. 3. The General Case Question: Yes. If item is less than tree->info, then we know that the node to be deleted is in tree's left subtree. Assuming that the recursive call successfully deletes from the left subtree, the problem is solved correctly. Otherwise, if item is greater than tree->info, we know that the node to be deleted is in tree's right subtree. Again, assuming that the recursive call successfully deletes from the right subtree, the problem is solved correctly. 27. template<class ItemType> void PrintAncestors(TreeNode<NodeType>* tree, ItemType value) const; // prototype template<class ItemType> void TreeType<ItemType>::Ancestors(ItemType value) const // Calls recursive function PrintAncestors to print the ancestors. { PrintAncestors(root, value); } template<class ItemType> void PrintAncestors(TreeNode<NodeType>* tree, ItemType value) const { if (tree->info != value) { std::cout << tree->info << endl; if (tree->info < value) PrintAncestors(tree->right, value); else PrintAncestors(tree->left, value); } } 30. int LeafCount(); // prototype // Post: Function value = number of leaf nodes in the tree. template<class ItemType> int Count(TreeNode<ItemType>* tree); // prototype template<class ItemType> int TreeType<ItemType>::LeafCount() // Calls recursive function Count to count the number // of leaf nodes. { return Count(root); } template<class ItemType> int Count(TreeNode<ItemType>* tree) { if (tree == NULL) return 0; else if (tree->left == NULL) && (tree->right == NULL) return 1; else return Count(tree->left) + Count(tree->right); } 33. (a) bool SimilarTrees(TreeType<ItemType> otherTree); // prototype // Post: True is returned if self and otherTree are similar; false // is returned otherwise. template<class ItemType> bool Similar(TreeType<ItemType>* tree1, TreeType<ItemType>* tree2); // prototype // Recursive function to determine if two trees are similar. (b) template<class ItemType> bool TreeType<ItemType>::SimilarTrees(TreeType<ItemType> otherTree) { return Similar(root, otherTree.root); } template<class ItemType> bool Similar(TreeNode<ItemType>* tree1, TreeNode<ItemType>* tree2); { if (tree1 == NULL && tree2 == NULL) return true; else if (tree1 == NULL && tree2 != NULL) || (tree1 != NULL && tree2 == NULL) return false; else return Similar(tree1->left, tree2->left) && Similar(tree2->right, tree2->right); } 35. template<class ItemType> void MakeTree(TreeType<ItemType>& tree, int info[], int length) // Creates a binary tree from a sorted array. { tree.MakeEmpty(); AddElements(tree, info, 0, length-1); } template<class ItemType> void AddElements(TreeType<ItemType>& tree, ItemType info[], int fromIndex, int toIndex) { int midIndex; if (fromIndex <= toIndex) { midIndex = (fromIndex + toIndex) / 2; tree.InsertItem(info[midIndex]); AddElements(tree, info, fromIndex, midIndex - 1); // Complete the left subtree. AddElements(tree, info, midIndex+1, toIndex); // Complete the right subtree. } } 38. Either the value in node 5 or the value in node 6. 40. Preorder 43. (a) Any negative number can be used as a dummy value. (b) Assume that the dummy value is -1.0. tree .numElements 13 .nodes [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] 26 14 38 1 -1 33 50 -1 7 -1 35 44 60 ? ? ? Chapter 9 2. The relational operator <= should be replaced with >=. 5. (a) The member functions would not change, but the private data members would change. The only data member would be a pointer to a linked lists. 8. (b) The code for SortedType::InsertItem (linked implementation) can be used directly with the relational operator reversed. (c) The code is identical to StackType::Pop. (d) Dequeue for a priority queue implemented as a linked list (ordered from highest to lowest priority) is very simple and efficient; we have direct access to the largest element. There is less work involved in fixing the structure after the largest element is removed, because the next-largest element immediately follows it. Thus the operation is 0(1). In the heap implementation we have immediate access to the largest element, but we have to perform a reheap operation to fix the structure, resulting in an O(log2N) operation. The linked list implementation is more efficient, in terms of Big O. When the priority queue is implemented as a linked list, the efficiency of Enqueue varies according to the position that the new element occupies in the list. If the new element belongs in the last position, the whole list is searched before the insert place is found. Thus the operation is O(N). Using heaps, the insertion operation is O(log2N). The linked list implementation might be better if the elements were inserted in largely sorted order from smallest to largest value. (a) The highest-priority element is the one with the largest time stamp. (This assumes that the time stamp never reaches INT_MAX. (b) Push Assign the next largest time stamp to the new element Put new element in the stack (position is unimportant) Pop Find the element with the largest time stamp Assign this element to item (to be returned) Remove the element (c) The Push operation has O(1) because it doesn't matter where the item is stored in the structure. The Pop operation has O(N), because the item with the largest time stamp must be searched for. Therefore, Push is the same in both implementations, but Pop is not. If the priority queue is implemented using a heap with largest value the highest priority, Pop and Push have O(log2N). 12. EmployeeGraph ..vertices .numVertices .vertexList [0] Brent [1] Darlene [2] Fran [3] Fred [4] Jean [5] John [6] Lance [7] Mike [8] Sander [9] Susan .Edges [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] F F F T F F T F F F F F F F F F F T F T F F F F F T T F T F T F F F F F F F F F F F F F F F T F F T F F T F F F F F F T T F T F T F F F F F F T F F F F F F F F F F T F F F F F F T F T F F T T F F T F [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] 14. "works with" is the best description of the relationship represented by the edges between vertices in EmployeeGraph, because it is an undirected graph. The other relationships listed have an order implicit in them. 17. The correct answer is (b). For example, a dalmatian is an example of a dog. 20. (a) StateGraph ..vertices .numVertices 7 .vertexList [0] Alaska [1] Californi a [2] Hawaii [3] New York [4] Oregon [5] Texas [6] Vermont .Edges [0] F F F F T F F [1] F F F F F F F [2] T T F T F T F [3] F F F F F F F [4] F F F F F F F [5] F F T F F F T [6] T T F T F F F [0] [1] [2] [3] [4] [5] [6] (b) ..vertices .numVertices 7 .vertexList [0] Alaska -> 4 [1] Californi a [2] Hawaii -> 1 [3] [4] [5] New York Oregon Texas -> 2 / -- -> 3 - -- -> 5 - -- -> 6 - / -- -> 0 - / [6] Vermont -> 0 -- -> 1 - -- -> 3 - / 23. Deleting a vertex is more complicated than deleting an edge for two reasons. First, in addition to removing the vertex from the set of vertices, we must also remove the edges to all its adjacent vertices in the set of edges. Second, we must dedecide what to do about the now unused vertex number. The best solution is to keep a list of returned vertex numbers and assign new numbers from there first. 25. Implicit set representations represent those items that are present in an instance of a set explicitly; those items that are not represented are not in the set. Explicit set representations associate a place (bit or Boolean flag) for each item in the base type in the instance of each set . The place for an item is true if the item is in the set and false if the item is not in the set. Chapter 10 1. (a) BubbleSort 4 5 7 10 [0] [1] [2] [3] (b) SelectionSort 4 5 7 10 [0] [1] [2] [3] (c) InsertionSort 7 10 23 43 [0] [1] [2] [3] 43 [4] 14 [5] 18 [6] 23 [7] 19 [8] 66 [9] 18 [4] 43 [5] 19 [6] 23 [7] 66 [8] 14 [9] 18 [4] 4 [5] 19 [6] 5 [7] 66 [8] 14 [9] 4. (a) bubble sort (b) selection sort (c) insertion sort 7. The correct answer is (c). 10. (a) Bubble sort is O(N) if the values are already sorted, and if the algorithm stop processing when the sorting is complete (like ShortBubble). (b) None. (c) QuickSort is O(N 2) if the values are already sorted and the split algorithm causes the array to be split into one element and the rest of the array. 13. (a) True (b) False. HeapSort is better for nearly sorted data than QuickSort. (c) True 16. The correct answer is (b). 19. The code is identical to the one in the book with the relational operator in the comparison changed. 22. Declare an array indexed from 0 through 99. Use the slots in the array as counters for that percentile score; that is, the slot indexed by 0 is the counter for percentile scores of 0; the slot indexed by 2 is the counter for percintile scores of 2; and so on. To produce the required output, go through the array from 99 down to 0, printing the loop counter as many times as there are values in that slot. 25. (a) for the best case. O(1) (b) for the worst case. O(N2) 28. dataValues 14 27 [0] [1] 95 [2] 12 [3] 26 [4] 5 [5] 33 [6] 15 [7] 9 [8] 99 [9] sortedValues 5 9 [0] [1] 12 [2] 14 [3] 15 [4] 26 [5] 27 [6] 33 [7] 95 [8] 99 [9] Search dataValues sequentially 8 10 1 6 10 10 1 Values 15 17 14 5 99 100 0010 Search sortedValues sequentially 5 6 4 1 10 10 3 BinarySearch sortedValues 1 3 4 3 4 4 3 Search tree 31. HashTable [0] [1] [2] [3] [4] [5] [6] [7] [8] 90 140 153 393 145 66 47 467 285 126 87 735 620 395 566 177 34. The correct answer is (a) 37. (a) 50 (b) 50 (c) 50. 40. The correct answer is (c). 43. No. Simply substituting the StackADT for the QueueADT would not work. The elements would be gathered in the wrong order. 4 4 1 3 4 4