(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.
10. (a)
// Sorts values from values[fromIndex] .. values[toIndex].
// proper place on each call.
13. (a)
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. (c) is the correct answer
5. (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)
10. Show what order the nodes in the tree are processed by
(a) BDJKMNPQRTWY
(b) BJDNPMKRWYTQ
(c) QKDBJMPNTRYW
13. (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.
14. (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
17. (a) False
(b) False
(c) True
(d) False
19. (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
void DeleteNode(TreeNode*& 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* 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
void PrintAncestors(TreeNode* tree, ItemType value) const;
// prototype
template
void TreeType::Ancestors(ItemType value) const
// Calls recursive function PrintAncestors to print the ancestors.
{
PrintAncestors(root, value);
}
template
void PrintAncestors(TreeNode* 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
int Count(TreeNode* tree); // prototype
template
int TreeType::LeafCount()
// Calls recursive function Count to count the number
// of leaf nodes.
{
return Count(root);
}
template
int Count(TreeNode* 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 otherTree); // prototype
// Post: True is returned if self and otherTree are similar; false
// is returned otherwise.
template
bool Similar(TreeType* tree1, TreeType* tree2);
// prototype
// Recursive function to determine if two trees are similar.
(b)
template
bool TreeType::SimilarTrees(TreeType otherTree)
{
return Similar(root, otherTree.root);
}
template
bool Similar(TreeNode* tree1, TreeNode* 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
void MakeTree(TreeType& tree, int info[], int length)
// Creates a binary tree from a sorted array.
{
tree.MakeEmpty();
AddElements(tree, info, 0, length-1);
}
template
void AddElements(TreeType& 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]
|
26
|
[1]
|
14
|
[2]
|
38
|
[3]
|
1
|
[4]
|
-1
|
[5]
|
33
|
[6]
|
50
|
[7]
|
-1
|
[8]
|
7
|
[9]
|
-1
|
[10]
|
35
|
[11]
|
44
|
[12]
|
60
|
[13]
|
?
|
[14]
|
?
|
[15]
|
?
|