CS2040 Tutorial7 Ans
CS2040 Tutorial7 Ans
Problem 1.a. (AY19/20 Sem 1 Final Exam) Given any AVL tree of height 4, deleting any
vertex in the tree will not result in more than 1 rebalancing operation (not rotation but rebalancing
operations!).
Solution: False. For the binary search tree below (found in the lecture notes), deleting vertex
7 triggers two rebalancing operations. Important: Note that a rebalancing operation is not the
same as a rotation: a rebalancing operation is one of the four rebalancing cases mentioned in the
lecture notes (left-left, left-right, right-left, right-right), and can consist of more than one rotation.
8
6 16
3 7 13 19
2 11 15 18
10
Problem 1.b. The minimum number of vertices in an AVL tree of height 5 is 21.
Solution: False. The minimum is 20. The minimum number of vertices nh in an AVL tree of
height h is given by the recurrence
n0 = 1
n1 = 2
ni = ni−1 + ni−2 + 1
Problem 1.c. In a tree, if for every vertex x that is not a leaf, x.lef t.key < x.key if x has
a left child and x.key < x.right.key if x has a right child, the tree is a BST.
1
Solution: False. Consider the following binary tree. Note that the above statement holds for
every node in the binary tree, but the binary tree is not a BST. For a binary tree to be a BST, you
need all vertices y in the left subtree of x to have y.key < x.key and not just the left child y of x
having y.key < x.key. Similar argument for vertices in the right subtree of x and the right child of
x.
10
5 12
3 20 11 23
Problem 2.b. Propose modifications to the successor function such that Algorithm 1 runs
in O(n) time.
Solution: Notice that in a standard in-order traversal, we perform something that is similar to
Algorithm 1 – we go one node to its successor, then from the next node, we go to its successor
again, and so on, until we visit all nodes in the BST. However, the difference is that in a standard
in-order traversal, we move directly from one node to its successor, instead of locating its successor
starting from the root node.
Hence, we can modify Algorithm 1 such that it works in a way similar to the standard in-order
traversal. In particular, for the successor function, we can get it to accept a reference to the node
that we want to find the successor of, so that we can begin searching for the successor from the
node itself, rather than from the root node.
2
Problem 3. Rank and Select
A node x has rank k in a BST if there are k − 1 nodes that are smaller than x in the BST. The
rank operation finds the rank of a node in a BST.
Problem 3.a. Describe an algorithm that finds the rank of a given node in the BST in O(h)
time, where h is the height of the BST.
Solution: Augment every node in the BST with the size of its subtree. Then, we can compute
the rank of a given node using the following algorithm.
The select operation returns the node with rank k in the BST.
Problem 3.b. Describe an algorithm that finds the node with rank k in the BST in O(h) time,
where h is the height of the BST.
Solution: Once again, we augment every node in the BST with the size of its subtree. Then, we
can find the node with rank k using the following algorithm.
3
j, as long as both servers are enabled, and all servers between them (if any) are all enabled as well.
Initially, all servers are enabled.
You need to support q of the following three types of operations:
Enable(i): Enable the ith server. If the ith server is already enabled, nothing happens.
Disable(i): Disable the ith server. If the ith server is already disabled, nothing happens.
Send(i, j): Return true if it is possible to send data from server i to j, f alse otherwise.
Describe the most efficient algorithm you can think of for each of the three types of
operations. What is the running time of your algorithm for each of the three types of
operations?
Solution 1: We can use a bBST to maintain the servers that are currently disabled. When a
server is disabled, we insert it into the bBST, and when a server is enabled, we remove it from the
bBST. To check if we are able to send a message from server i to server j, we need to check that i
is not in the bBST, and either i has no successor in the bBST, or the successor of i in the bBST is
greater than j.
Here, we note that the successor of x, or successor(x), refers to the node in the bBST containing the
smallest key that is greater or equal to x. This definition of successor is similar to the higherEntry
method in the Java TreeMap. A simple way to implement this is to first do a search to check for
existence, then do an insertion and call the usual successor, and then doing a deletion. However,
there is way to do this directly without any insertions or deletions by modifying the search operation,
and is left as an exercise.
Solution 2: Another even simpler way of implementing the 3 operations is as follows. Maintain
a bBST that contains the servers which are currently enabled. When a server is enabled, insert
it into the bBST if it is not already in the bBST. Similarly when a server is disabled, remove it
from the bBST if it is not already removed. To check if we can send a message from server i to
4
server j, first check if both i and j exist in the bBST. If both exist, get rank(i) and rank(j). If
rank(j)-rank(i) = j-i then i can send a message to j since every server in between must be enabled.
Otherwise i cannot send a message to j.
If either a or b is the same value as the current node, we can stop and we have found our
LCA.
If a and b are both smaller than the value at the current node, we move to the left child of
the current node and it becomes the new current node.
If a and b are both greater than the value at the current node, we move to the right child of
the current node and it becomes the new current node.
If a is smaller than the value at the current node, and b is greater than the value at the
current node, then the current node is the LCA. This is also true if we swap the positions of
a and b.
The algorithm takes O(log n) time and O(1) space, since the BST is now balanced.