Exam Booklet
Exam Booklet
EXAMINATION BOOKLET
• No food or drinks (other than water) are allowed into examination room.
• Ensure your mobile phone (or any electronic devices including digital watches) is switched off and put away.
• Place your Student ID card on your desk.
• Communication with anyone other than the course instructor or proctor is not allowed at any time during the exam.
• The exam is open-book; you are allowed to use the PDF lecture notes provided with the exam files. Access to any
other material (e.g., Moodle, the Internet, or other resources) is not allowed
• Please keep your eyes on your own paper/computer at all times.
• If you face a problem during the exam, please raise your hand and quietly wait for the proctor.
• Do not open the examination booklet until directed to do so.
• At the conclusion of your exam, refrain from speaking until after you have exited the exam room.
• The exam parts are of variable difficulty, so make sure you manage your time well and solve all the easy parts
first.
• Submission: The exam consists of two parts for a total of 100 points:
o 4 Conceptual problems: provide handwritten answers on the provided answer booklet
o 4 Coding problems: submit one cpp file per coding problem. Please follow this naming convention for
each cpp file: p#_firstName_lastName.cpp where p# is the problem number (as numbered in the exam
booklet)
• Luck favors those who are well prepared.
Conceptual Problems [40 points]
C1 – GREEDY ALGORITHMS
a) [2 points] What is a greedy algorithm?
b) [4 points] Name two graph algorithms that are greedy and say why they are considered so.
c) [2 points] Name a data structure that is often useful to efficiently implement the greedy-choice selection.
C2 – DAY-STOUT-WARREN
[10 points] Recall from class the DSW algorithm to balance a binary tree. Starting from a sorted linked list with 15
elements (assume for simplicity that they are the integers 1, 2, 3, …, 15), create a complete binary tree using the
DSW algorithm. To get full credit, you should show all the steps in the algorithm and the final tree. Note: you do not
need to redraw the whole tree for every single small change; you can show multiple steps on the same drawing
(e.g., cross-out some links and show new connections in different colors).
Design a data structure to represent this game and describe/name an algorithm to find the minimum number of
dice throws needed to move from any given source cell to a given destination cell.
C4 – YOUNG TABLEAUS
An 𝑚 × 𝑛 Young tableau is an 𝑚 × 𝑛 matrix such that the entries of each row are in sorted order from left to right
and the entries of each column are in sorted order from top to bottom. Some of the entries of a Young tableau may
have the value of positive infinity (∞), and these are treated as empty elements (although there position in the
matrix should still conform to the mentioned constraints by considering them larger than any finite value).
a) [4 points] Argue that an 𝑚 × 𝑛 Young tableau Y is empty if the top-left element Y[0][0] is ∞ and that it is
full if the bottom-right element is finite (Y[m-1, n-1] <∞).
b) [8 points] Provide O(𝑚 + 𝑛) running time algorithms for the following operations:
o EXTRACT-MIN from a nonempty 𝑚 × 𝑛 Young tableau
o INSERT a new element into a nonfull 𝑚 × 𝑛 Young tableau
o SEARCH for an element in a given 𝑚 × 𝑛 Young tableau
c) [2 points] Using no other sorting method as a subroutine, show how to use a Young tableau to sort 𝑛2
numbers in 𝑂(𝑛3 ) time.
P1 – DO NOT OVERTHINK
[5 points] Write a C++ program that prompts the user to enter two integers, separated by spaces, then prints their
sum and their product.
Sample input/output:
P2 – VECTOR
a) [9 points] Create a class Vector which represents a vector of integers < 𝑣0 , 𝑣2 , 𝑣3 , … 𝑣𝑛−1 >. The class
includes:
o private unsigned int data field 𝑛 representing the size of the vector
o private vector of integers storage to hold the vector elements
o A two-arguments constructor that initializes the two fields
o Overloaded operator[ ] that takes an integer 𝑖 and returns storage[𝑖]
o Overloaded operators: +, −, and ∗ which take another Vector instance and return the result of the
operations: self + other, self – other, and self*other, respectively, where:
- < 𝑥0 , 𝑥1 , … 𝑥𝑛−1 > + < 𝑦0 , 𝑦1 , … 𝑦𝑛−1 > = < 𝑥0 + 𝑦0 , 𝑥1 + 𝑦1 , … 𝑥𝑛−1 + 𝑦𝑛−1 >
- < 𝑥0 , 𝑥1 , … 𝑥𝑛−1 > − < 𝑦0 , 𝑦1 , … 𝑦𝑛−1 > = < 𝑥0 − 𝑦0 , 𝑥1 − 𝑦1 , … 𝑥𝑛−1 − 𝑦𝑛−1 >
- < 𝑥0 , 𝑥1 , … 𝑥𝑛−1 > ∗ < 𝑦0 , 𝑦1 , … 𝑦𝑛−1 > = 𝑥0 ∗ 𝑦0 + 𝑥1 ∗ 𝑦1 + ⋯ + 𝑥𝑛−1 ∗ 𝑦𝑛−1
Note 1: that while the + and – operations return vectors, the * operation returns a scaler (dot product)
Note 2: the vector sizes should be compatible otherwise, the operations throw an exception
b) [4 points] Overload the operator << to allow printing a vector in the format above <…> as follows:
ostream object << Vector object << …
P3 – BST METHODS
Update the code in BST.cpp (given with exam files) as follows:
a) [3 points] Update the BST class and the test in main so that the data in each BSTNode is of type int, so now
the BST class is not generic (i.e., no type T).
b) [8 points] Add the method list<int> toSortedList( ) which returns a sorted list view of the tree, i.e., it
returns an STL list containing all the data values in the tree (recall: you can use the push_back method to
add elements to a list). The resulting list should be sorted from smallest to largest, and the method should
obtain its result in O(𝑛) time and O(1) space (i.e., no more than O(1) auxiliary space other than the list
itself).
c) [10 points] Add the method int evenGrandparentSum( ) which returns the sum of data values of all the
nodes in the tree whose grandparent (if a grandparent exists) has an even data value. If no such nodes exist
or if the tree is empty, then the method returns 0. Note: you are not allowed to add a parent attribute to
BSTNode.
Tree contents:
7
2 8
1 3 11
5 9 23
4 6 12 109
Even grandparent sum = 37
Sorted list view: 1 2 3 4 5 6 7 8 9 11 12 23 109
P4 – HASHTABLE
The HashTable.cpp file is given to you; it includes an incomplete implementation of a HashTable data structure.
The table is implemented using a vector of HashNode pointers (each representing the head of a linkedlist), where
each linkedlist represents a bucket (i.e., collision chain) of HashNodes, and each HashNode contains a key-value
pair and a pointer to the next HashNode in the chain. Complete the implementation as detailed below.
b) TODO 1 [8 points]: Implement the method insert which takes as arguments a key and a value. The method
first checks if the table size has reached capacity, in which case it throws "Capacity exceeded!".
Otherwise, if the given key does not already exist in the table, the method increments the table size and
inserts a new HashNode with the given key-value pair at the head of the linkedlist at index 𝑖 of the table,
where 𝑖 is obtained by calling the getBucketIndex(key) method. If the key already exists, then its value is
updated to the given value (i.e., the method updates an existing HashNode instead of inserting a new one).
c) TODO 2 [6 points]: Add a get method which takes two arguments: a key (type K) and a value (type V),
where value is passed by reference (it represents an output). The method efficiently searches for the given
key in the table:
o If key is found, the method updates value to be the value associated with key and returns true
o If key is not found, the method returns false
d) TODO 3 [3 points]: Add a HashTable destructor that destructs (deletes) all the table HashNodes.
e) TODO 4 [4 points]: Update the test in main where you add a test for the get method (one that finds the key
and one that doesn’t) and also insert more keys into the table until capacity is reached. Handle and print the
exception that is thrown. A sample output is shown below.
Sample output:
Table size = 14
Table empty? No
Testing the get method:
Test 1: value = 11
Test 2: key does not exist!
Capacity exceeded!