CPSC 331 Practice Midterm 1 Fall 2022
CPSC 331 Practice Midterm 1 Fall 2022
Name:
Instructions:
1. Answer all questions in the space provided using a dark pen or pencil. Continue
answers on the final page if you need more room.
3. One double-sided letter-sized page of notes is allowed. No other aids are allowed.
Duration: 90 minutes
ID Number:
(3 marks) (a) Describe how an array (or ArrayList) A can be used to implement a bounded
stack. Where should the value at the bottom of the stack be stored in the array
(if this stack has size n and the array has length m ≥ n)? Where should the
value at the top of the stack be stored, if stack operations are to be implemented
efficiently? Where should the other values on the stack be stored?
(2 marks) (b) Give (very short) pseudocode or a description in English for a method to remove
(or “pop”) value x from a stack when this array-based implementation is being
used — assuming that the size n of the stack is also being stored.
ID Number:
3 10
1 8 12
(3 marks) (a) Draw the binary search tree that would be obtained from the above one by
deleting 6 from the set represented by this binary search tree.
(2 marks) (b) Using asymptotic notation, state the number of operations used to delete a
value from the set represented by a given binary search tree with size s and
depth d, as a function of either s or d. While asymptotic notation must be used
you should try to make your bound as precise as you can.
ID Number:
Depth of Subtree
Precondition: A node x in a binary search tree T is given as input.
Postcondition: The depth of the subtree of T with root x is returned as
output.
(1 mark) (a) Fill in the blanks at line 3 in the following algorithm, to complete a recursive
algorithm that correctly solves the “Depth of Subtree” problem.
integer sDepth(node x) {
1. if (x is null) {
2. return −1
} else {
3. return 1 + max( , )
}
}
(7 marks) (b) Prove the following.
Claim: If the sDepth algorithm is executed with a node x in a binary
search tree T as input then the execution of the algorithm ends, and
the depth of the subtree of T with root x is returned as output.
Proof of Claim:
ID Number:
(2 marks) (c) Using asymptotic notation, state the number of operations used by the sDepth
algorithm in the worst case, as a function of either the depth d or the the size s
of the binary search tree T that includes the input node x. While asymptotic
notation must be used you should try to make your bound as precise as you
can.
ID Number:
(2 marks) (a) First consider hashing with chaining — the kind of hashing described in the
first lecture on hash tables — using table size m = 10 and using the following
hash function to store integers:
Draw the hash table that would be produced by inserting the values
(8 marks) (b) Discuss the number of comparisons of keys used to search for a given key in
a hash table (using hashing with chaining, as above). Your discussion should
include
• the number of comparisons used in the worst case,
• assumptions that are made when an average case analysis of searches in
a hash table,
• the expected number of comparison used to search, when these assump-
tions hold, and
• whatever is known about the number of comparisons used to search, when
these assumptions do not hold.
The bounds that you might give might depend on the size N of the universe U
from which keys are chosen, an upper bound n on the size of the subset of U
that is currently being represented, and the table size m for the hash table being
used.
ID Number:
ID Number:
ID Number:
(a) You were first asked to describe how an array (or ArrayList ) A can be used to implement
a bounded stack. You were asked where the value at the bottom of the stack be should
stored in the array and (if this stack has size n and the array has length m ≥ n), where the
value at the top of the stack should be stored, if stack operations are to be implemented
efficiently, and where the other values on the stack should be stored.
(b) You were next asked to give pseudocode or a description in English for a method to remove
(or pop) a value x from a stack when this array-based implementation is being used —
assuming that the size of the stack is also being stored.
Method To Pop a Value Off of a Stack — Brief Description in English: If the stack is
already empty — so that its size is already 0 — throw an exception and do not change
the array. Otherwise set x to be the value A[size − 1], decrement size and return x.
if (size == 0) {
throw a NoSuchException
} else {
x = A[size-1];
size = size − 1;
return x;
}
(a) To begin, you were asked to consider the following binary search tree.
3 10
1 8 12
You were asked to draw the binary search tree that would be obtained from the above one
by deleting 6 from the set represented by this binary search tree.
Solution: The tree obtained by deleting 6 from the set represented by this binary search
tree is as follows.
3 10
1 12
Note: It is also acceptable to overwrite the value at the node you start from with the largest
value in the left subtree of this node, instead of using the smallest value in the right subtree
of this node. In this case, the binary search tree obtained by deleting 6 would be as follows.
1 10
8 12
(b) Using asymptotic notation, you were asked to state the number of operations used to
delete a value from the set represented by a given binary search tree with size s and
depth d, as a function of either s or d.
Solution: The number of operations used to delete a value from the set represented
by a binary search tree with size s and depth d is in Θ(d), in the worst case. That is,
the maximum number of operations used for any deletion from this binary search tree is
in Θ(d).
Depth of Subtree
Precondition: A node x in a binary search tree T is given as input.
Postcondition: The depth of the subtree of T with root x is returned as
output.
(a) You were asked to fill in the blanks at line 3 in the following algorithm, to complete a
recursive algorithm that correctly solves the “Depth of Subtree” problem.
integer sDepth(node x) {
1. if (x is null) {
2. return −1
} else {
3. return 1 + max( , )
}
}
Proof. This will be proved by induction on the size of the subtree of T with the input node x
as its root. The strong form of mathematical induction will be used, and the case, that the
size of the subtree with root x is 0, will be considered in the basis.
Basis: If the size of the subtree of T with root x is 0 then this subtree is empty and has
depth −1, so that −1 should be returned as output.
Now, sincex is the root of an empty subtree, x is null. Consequently, when the sDepth
is executed with input x the test at line 1 is passed, the step at line 2 is reached, and the
execution halts with −1 is returned as output, as required for this case.
Inductive Step: Let k be an integer such that k ≥ 0. It is necessary and sufficient to use
the following
With that noted, let T be a binary search tree and suppose that the sDepth algorithm is
executed with a node x in T as input, where the size of the subtree of T with root x is k + 1.
Since k ≥ 0, k + 1 ≥ 1, and the subtree of T with root x is not an empty tree (size its size
is at least one). Thus x is not a null node. Now consider the following values.
Note that, since Tx is the subtree of T with root x, it is necessary and sufficient to show
that the algorithm of the sDepth algorithm with input x halts, and returns dx , in order to
establish the Inductive Claim.
Now consider this execution of the algorithm. Since x is not null the test at line 1 fails, so
that the step at line 3 is returned and executed.
• This step includes a recursive application of the sDepth algorithm with the left child
of x as input.
Since the size of Tx is k + 1, and the left and right subtrees of Tx have sizes sL
and sR , respectively, it follows that sL and sR are both integers such that sL , sR ≥ 0
and
k + 1 = sL + sR + 1.
it follows from that that 0 ≤ sL , sR ≤ k . If particular, 0 ≤ sL ≤ k and, since sL is
the size of the subtree of T with the left child of x as root, it follows by the Inductive
Hypothesis that this first recursive execution of the algorithm ends, with the depth,
dL , of this left subtree of Tx returned as output.
• This step also includes a recursive application of the sDepth algorithm with the right
child of x as input. As noted above, the right subtree of Tx has size sR , and sR is
an integer such that 0 ≤ sR ≤ k . Since sR is the size of the subtree of T with the
right child of x as root, it follows by the Inductive Hypothesis that this second recursive
execution of the algorithm ends, with the depth, dR , of this right subtree of Tx returned
as root.
• Thus the value returned by this execution of the algorithm. when the step at line 3 id
executed, is
1 + max(dL , dR ).
Since dL and dR are the depths of the left and right subtrees of Tx , respectively,
this is the depth of Tx — as needed to establish the Inductive Claim, completing the
Inductive Step.
The claim now follows by induction on the size of the subtree of T with root x.
Note: There is more than one way to prove this claim! For example, it can also be proved
by induction on the depth of the subtree with root x (and you should understand what that
proof would look like too).
(c) You were asked to use asymptotic notation to state the number of operations used by the
sDepth algorithm in the worst case, as a function of either the depth d or the the size s of
the binary search tree T that includes the input node x.
Solution: The number of operations used by the sDepth algorithm, in the worst case, is
in Θ(s), where s is the size of the binary search tree T whose depth is being computed.
Note: You were not asked to prove this. However, this can be proved by forming a re-
currence for the number of operations used, and then using mathematical induction to
prove that the number of operations used is at most 4s + 2. On the other hand, it is also
reasonably easy to show that at least 2s operations must also be used, too.)
This question concerned the use of hash tables to store finite sets.
(a) Consider hashing with chaining — the kind of hashing described in the first lecture on
hash tables — using table size m = 10 and using the following hash function to store
integers:
h(x) = x (mod 10).
You were asked to draw the hash table that would be produced by inserting the values
0 30 10 20 0
1
2
3
4
5 5
6
7
8
9
(b) You were asked to discuss the number of comparisons of keys used to search for a given
key in a hash table (using hashing with chaining, as above). Your discussion should include
The bounds that you might give might depend on the size N of the universe U from which
keys are chosen, an upper bound n on the size of the subset of U that is currently being
represented, and the table size m for the hash table being used.
Solution: Consider the number of comparisons of keys used to search for a key in a hash
table, using hashing with chaining — to represent finite subsets of a universe U whose
sizes are at most n, with a hash table whose table size is m.
• The number of comparisons of keys used, in the worst case, is the same as the
number that would be used if they keys were stored in a singly linked list — so that
this is Θ(n).
• Searches can be either unsuccessful or successful, and different assumptions
were used, and results obtained, for each kind of search.
– For unsuccessful searches it is assumed that we search for some value x
such that h(x) = i with the same probability, 1/m, for every integer i such that
0 ≤ i ≤ m − 1.
Under this assumption, it was proved that the expected number of comparisons
used for an unsuccessful search is ℓ/m, that is, the load factor α = ℓ/m of the
hash table being used.
– For successful searches an assumption was made about the shape of the hash
table, and this was given as an assumption about how the hash table was cre-
ated. In particular, it was assumed that (when a set with size ℓ ≤ n is being
represented, the hash table looks like it was created by inserting a sequence of
ℓ keys
k1 , k2 , . . . , kℓ
(for distinct k1 , k2 , . . . , kℓ ∈ U ) into an initially empty hash table and that each of
the mℓ sequences of values of hash values
α1 , α2 , . . . , αℓ (1)
Things to Notice:
• Notice how the answer starts by reviewing what is to be discussed (with notation to be
used) and is has an organization based on the list of questions that you were asked
to make sure to answer. This kind of answer is relatively easy to write and easy to
assess, because it makes easy for information to find when this is being looked for.
• The parameter, n, is used in two related ways in the lecture notes about hash tables:
Sometimes it is an upper bound for the size of the subset being represented, and
sometimes it as being used to represent the size of that subset, instead. The question
used n as an upper bound for the size of the subset, so the answer used a different
parameter, ℓ, as the size of the subset, in order to avoid using “n” in two different
ways. Note that if ℓ and n are as describe here then 0 ≤ ℓ ≤ n.
Yes, you will sometimes have to modify material that you are using, in order to adjust
for things like differences in the ways that parameters are used. If you don’t do this
(which often happens when you do not really understand the material you are using)
then your answer will probably not make any sense, and will be marked accordingly.
• Asymptotic notation is, sometimes, being used to state bounds, here. Questions will
often be worded to say whether this is allowed (or required) — and you should ask
about this, during a test, if this is not clear.
• The answer includes a “numbered equation” so that the information at line (1) could
be referred to, later on, in a way that would make it easy for a reader to find this
information again. You can do the same thing soon, even when you are writing your
answer out instead of typesetting it.