Data Structures II Final Prep

Ace your homework & exams now with Quizwiz!

For Q2's postfix expression: 1 2 4 + 5 * 15 / + While running the 2nd algorithm (Evaluating Postfix Expression) taught in the Stack lectures, what are the first two elements that will be popped from the stack? a. 2, 4 b. 1, 2 c. 5, 15 d. 4, 5

a When we encounter the first "+", the stack has 1, 2 and 4. We pop the top two elements in the stack, which are 2 and 4.

To implement the insert 2-parameter function in doubly linked list class template, given the iterator whose current points to the position of a node, and a desired value that will be inserted before the position that current is pointing at, which of the following is the right order in the implementation? a. Use new to declare a new Node, set its value to be the desired value, and link its prev and next appropriately; b. Modify the Node that will be on the left side of the inserted value such that this Node's next will point to the new Node; c. Modify the Node that will be on the right side of the inserted value such that this Node's prev will point to the new Node. d. theSize increments by 1; e. Return the address of the new Node.

a -> b -> c -> d -> e It's not d -> b -> c -> a -> e because b and c cannot occur before a, which is because b and c require the address of the new Node to work. It's not a -> c -> b -> d -> e because to execute b, we use prev of the current of the iterator in the input parameter to find the Node that will be on the left side of the inserted value. But if we execute c first, the prev of the current of the iterator in the input parameter would point to the new Node after c is executed, thus we lose the address of the Node that will be on the left side of the inserted value. Thus b has to occur before c instead of after c.

To implement the erase 1-parameter function in doubly linked list class template, given the iterator whose current points to a Node that is to be erased, which of the following is the right order in the implementation? a. Record the next of the Node that current of the iterator is pointing at so that we can return it. b. Modify the Node that is on the left side of the Node to be erased such that this Node's next will point to the Node on the right side of the Node to be erased; c. Modify the Node that is on the right side of the Node to be erased such that this Node's prev will point to the Node on the left side of the Node to be erased; d. Deallocate the memory that the current of the iterator is pointing at. e. Reduce theSize by 1. f. Return the iterator whose current points to the Node that is on the right side of the Node that has been erased.

a -> b -> c -> d -> e -> f It cannot be b -> c -> d -> e -> a -> f because a has to happen before d. If we already deallocate the memory that the current of the iterator is pointing at, then we lose track of the address of the Node that is on the right side of the Node which has been erased.

For the same tree in the previous question, write its infix expression. Add necessary parenthesis. Do NOT add unnecessary parenthesis. Each pair of neighboring tokens shall be separated by one blank. Parenthesis is treated as a token.

( 4 + 5 ) * 10 / ( 2 * 3 ) Infix expression traverses the tree in an inorder. Parenthesis is added when the parent and child are both operators, and the child's precedence is smaller than the parent's, or the child is a right child and its precedence is the same as the parent's (seen in slides 29-30 in tree2.pdf in Module 9.1).

If the current TableSize is 7. By using the formula nextPrime(2 * TableSize), what is the TableSize after rehashing?

17 Twice of 7 is 14. We find the smallest prime number that is greater than 14, thus 17.

Given the postfix expression: 1 2 4 + 5 * 15 / + Evaluate this postfix expression manually using the 2nd algorithm taught in the Stack lectures. Give only the value itself, without any spaces or other symbols.

3 You can figure out the order of the operators by the 2nd algorithm presented in Stack. FYI, the infix expression of this postfix expression is: 1 + ( 2 + 4 ) * 5 / 15.

What is the postfix of this infix expression? 3 + 30 / 2 * (15 - 2)

3 30 2 / 2 * (15 - 2)

Given the following expression tree, write its corresponding postfix expression. Each pair of neighboring tokens shall be separated by one blank. / / \ x x / \ / \ + 10 2 3 / \ 4 5

4 5 + 10 * 2 3 * / Postfix expression navigates the tree in a postorder.

Suppose we have two functions f(N) and g(N). f(N) = O(g(N)) means that A. f(N) is upper bounded by g(N). B. f(N) is lower bounded by g(N). C. f(N) has the same long-term rate of growth as g(N).

A

Which of the following code line defines a vector which has 12 integers, i.e., the size of the vector is 12? A. vector<int> a(12); B. vector<int> a{12};

A B defines a vector of size one and the value of this only entry is 12, whereas A defines a vector of size 12.

Suppose we have two functions f(N) and g(N). f(N) = O(g(N)) if and only if there exist two positive constants c > 0 and n0 > 0, such that for all N >= n0, A. f(N) <= cg(N) B. f(N) >= cg(N) C. f(N) == cg(N)

A Definition of Big O notation. g(N) is the upper bound of f(N).

Of the following, which one is the most important purpose of using std::move()? A. To avoid copies thus save running time and space B. To make the code succinct C. To save programmers' time D. To make the code look nicer

A It is mainly to avoid copy, which takes running time and space.

Suppose a class is named "IntCell". Y is the name of an object of class IntCell and Y has already been declared and initialized. Which of the following Big-Five will be called in this line of code: IntCell X = Y ? A. Copy constructor B. Copy assignment operator= C. Move constructor D. Move assignment operator=

A It is the copy constructor because 1) X has not existed yet before this line of code, thus the answer should be a constructor; 2) Y is not an R-value (it has a name). Thus the answer is copy constructor, not move constructor.

Which of the following is the true definition of a POT? A. For any vertex p and any child c of p, p <= c. B. For any vertex p and its left child c1 and right child c2, c1 <= p, p <= c2.

A POT's definition is A. A totally ordered tree that was used in defining a binary search tree has the definition described in B.

In separate chaining, each row of the hash table stores A. a list of data entries B. one or zero data entry

A Separate chaining's data structure is a vector of a list, defined as follows vector<list<HashedObj>> theLists;

What is the complexity of rehash for both separate chaining and quadratic probing strategies, suppose after rehash, the TableSize is much larger than the number of elements in the hashtable? A. O(N) B. O(logN) C. O(1) D. O(N2)

A Since each entry needs to be inserted to the new hash table during rehash, and each insertion is counted as O(1), in total it is O(N). Notice that probing's insertion may take more time than separate chaining. But we typically assume that after rehashing, the table is not full. With the quadratic probing strategy, the data items are not clustered together. Thus it is safe to assume O(1) for insertion for probing strategy as well.

Suppose we have the following code: vector<int> square{1, 2, 3, 4, 5}; for (auto x : square) { ++x; } for (auto x : square) { cout << x << ","; } What is the output? A. 1,2,3,4,5, B. 2,3,4,5,6,

A Since we didn't use auto &x, but auto x, x is a local variable that is destroyed after being added 1. Thus the vector square's elements do not change at all. To get the result such as B, we have to use auto &x instead of auto x.

What is the complexity of the following code? for (j = 0; j < N; ++j) { int a = j + 1; for (k = 0; k < N; ++k) { int b = a + k; if (b == 100) break; } } A. O(N^2) B. O(N^3) C. O(N) D. O(logN)

A The algorithm has a for loop inside another. The inner for loop has two atomic operations per loop (as we consider the worst scenario case when the break will not happen), and the outer for loop has one operation per loop. So the total number of atomic operations is N ( 1 + N * 2 ) = 2N2 + N. Since we only consider the highest order and do not consider the constant, the complexity of the algorithm is O(N2).

Suppose arr is a pointer that has been initialized using int * arr = new int[16]; If we want to deallocate the memory (16 cells of integer type) that arr is pointing at, which one of the following command shall be used? Note: this question focuses on deallocation of the memory, not arr itself. A. delete [] arr; B. delete arr; C. arr = nullptr;

A To deallocate the memory, we use delete [] arr. If arr is defined as int * arr = new int; Then to deallocate the memory, we use delete arr. After deallocating the memory, if we do not redirect arr using command such as arr = new int[16], it is appropriate to make it nullptr: arr = nullptr;

In IntVector class, if we want to insert an element, but before we insert it, we find that the calling object's size is the same as the capacity (meaning that there is no room for one more element to be inserted). Which function will be called to increase the capacity before we insert the element? A. reserve B. resize C. move version of insert D. copy version of insert E. it is not necessary to increase the capacity

A We have to increase the capacity and the reserve function can do that. What reserve function does is first, it dynamically allocates a new space given the desired capacity. It then copies each element of the data from the previous storage to the new storage. After that, it deallocates the memory of the previous storage. Finally, it redirects arr to the newly allocated storage.

A heap is a A. Partially ordered tree B. Complete binary tree C. Totally ordered tree D. Binary search tree

A, B A heap is a partial ordered complete binary tree. Thus A and B.

Which of the following are the benefits of rehashing? A. In probing strategy, it avoids the hashtable from getting full. B. In separate chaining strategy, each data entry's position will be changed due to that the TableSize changed. Therefore rehashing helps to reduce the length of some lists, and further reduce the search time. C. For both probing and separate chaining strategy, it increases the TableSize so that more spaces are allowed for the subsequent insertions.

A, B, C All of these three are the benefits of rehashing.

Which of the following can accept an R-value? A. Pass by value B. Pass by L-value reference C. Pass by const reference D. Pass by R-value reference

A, C, D Only B cannot take an R-value because pass by L-value reference is supposed to be able to change the original variable via a function call, but an R-value cannot be changed. Pass by value takes an R-value because it makes a copy of it. Pass by const reference guards that the R-value will not be changed. Pass by R-value reference is designed to take R-values.

Choose the right order of functions that has an increasing growth rate: A. c, N, logN, log^2N, N^2, N^3, 2^N B. c, logN, log^2N, N, N^2, N^3, 2^N C. logN, log^2N, c, N, N^2, N^3, 2^N D. c, logN, N, log^2N, N^2, N^3, 2^N

B

Suppose we have two functions f(N) and g(N). f(N) = Ω(g(N)) means that A. f(N) is upper bounded by g(N). B. f(N) is lower bounded by g(N). C. f(N) has the same long-term rate of growth as g(N).

B

Suppose we already declared and initialized objects X and Y which are both of class IntCell. Which of the following Big-Five will be called for this line of code: X = Y? A. Copy constructor B. Copy assignment operator= C. Move constructor D. Move assignment operator=

B It is the copy assignment operator= because 1) X already exists, thus the answer should be an assignment instead of constructor; 2) Y is an L-value (it has a name), thus the answer is not a move assignment, but a copy assignment.

Suppose the estimated running time of an algorithm f(N) = 4N^4 + 10N^3 + 2N^2 + 10, in which N is the input size. Which of the following is this algorithm's tightest upper bound in the Big O notation? "Tightest" means you can NOT find a g(N) and n0 > 0, such that g(N) is smaller than this tightest upper bound for ∀N > n0. A. O(4N^4) B. O(N^4) C. O(4N^4 + 10N^3 + 2N^2 + 10) D. O(N^10)

B To get the tightest upper bound, we need to 1) ignore the lower orders; 2) ignore the constant. Thus O(N4) is the tightest upper bound.

What is the worst case running time for a heap for one insertion? A. O(N) B. O(logN) C. O(N2) D. O(1)

B Worst case happens when the inserted item has to go all the way up to the root, the number of comparison of which has to be done equals the height of the tree. Since the tree is a complete binary tree, its maximum height is known (logN) when the number of nodes is known (N). Thus the worst running time for an insertion is O(log(N)).

During a function call, if one wants to change the value of a variable without copying it, which of the following shall be used? A. Pass by value B. Pass by reference C. Pass by const reference

B a copies the value. c does not copy but cannot change the value of the variable. Only b allows change but not have to copy.

Suppose we have two functions f(N) and g(N). f(N) = Ω(g(N)) if and only if there exist two positive constants c > 0 and n0 > 0, such that for all N >= n0, A. f(N) <= cg(N) B. f(N) >= cg(N) C. f(N) == cg(N)

B g(N) is the lower bound of f(N).

Suppose we have the following code: string x = "hello"; string & y = x; y = "hi"; cout << x; What is the output? A. hello B. hi

B x and y refer to the same string. When y is changed, x is also changed. Thus the answer is "hi".

For a class that has the Big Five implemented, which of the following return(s) a reference to the calling object? A. Copy constructor B. Copy assignment operator= C. Move constructor D. Move assignment operator= E. Destructor

B, D The assignment operator= (for both copy and move versions) has the return, which is a reference to the calling object itself. This is to enable cascading assignment. For example, in IntVector example, the following code is possible due to the return of the copy assignment operator=. IntVector a1; IntVector a2( 5 ); IntVector a3 = a1 = a2; In the last line of code, a1 = a2 is run first (which runs the copy assignment operator=), returning a reference to a1. Then IntVector a3 = (a1 = a2) is run. Since there is a return from a1 = a2, we can assign this return value (which is a reference to a1) to a3 using copy constructor. Thus cascading assignment has been executed in this line of code.

Suppose we have two functions f(N) and g(N). f(N) = Θ(g(N)) means that A. f(N) is only upper bounded, not lower bounded by g(N). B. f(N) is only lower bounded, not upper bounded by g(N). C. f(N) has the same long-term rate of growth as g(N).

C

T/F To use std::move, which one of the following shall be included? A. #include <vector> B. #include <string> C. #include <utility>

C <utility> shall be #include to use std::move.

To have an instance of IntCell, we use the following code to define obj1-4. Which one is absolutely wrong? A. IntCell obj1; B. IntCell obj2{12}; C. IntCell obj3(); D. IntCell obj4{};

C C is a function call instead of a constructor call. If using a zero parameter constructor call, then we should use A, rather than C. Both B and D are legitimate. B calls the one parameter constructor, whereas D calls the zero parameter constructor.

How many std::move have been used in the std::swap template function? A. 1 B. 2 C. 3 D. 4

C It is 3 std::move that are used in std::swap function template.

Suppose class IntCell has operator+ overloaded, and Y is the name of an object of class IntCell that has already been declared and initialized. Which of the following Big-Five will be called in this line of code: IntCell X = Y + 13 ? A. Copy constructor B. Copy assignment operator= C. Move constructor D. Move assignment operator=

C It is move constructor because 1) X did not exist before this line of code, thus it is a constructor; 2) The rhs is Y+13 which is an R-value (it does not have a name), thus it is a move constructor, not a copy constructor.

To use std::swap, which one of the following shall be included? A. #include <vector> B. #include <string> C. #include <utility>

C Like std::move, to use std::swap, you have to #include <utility>. std::swap has 3 std::move inside the function.

In IntVector class, when increasing the capacity, which of the following is the right procedure and order? a. Make the pointer of the calling object arr the same as pointer "temp". b. Deallocate the space that the pointer of the calling object arr is pointing at. c. For every element stored in the dynamic array that the calling object arr points at, copy it to the corresponding space that "temp" is pointing at. d. Dynamically allocate the space for a new array whose size is set to be the desired capacity. Name the pointer pointing to this new space "temp". A. d, c, a, b B. b, a, c, d C. d, c, b, a D. a, b, c, d

C The correct order is 1. allocate new space and use a different pointer to point this space (temp); 2. copy elements in the array to where temp is pointing at; 3. deallocate the old array since we already have a deep copy of it; 4. assign temp to arr so that arr is pointing at the space that temp was pointing at.

During a function call, if one wants to pass the value of a variable without copying it or changing it, which of the following should be used? A. Pass by value B. Pass by reference C. Pass by const reference

C c does not allow the change of the variable itself, neither does it copy the value. a forces a copy, whereas b allows the change of the variable. Thus c.

Suppose we have two functions f(N) and g(N). f(N) = Θ(g(N)) if and only if there exist three positive constants c1 > 0, c2 > 0 and n0 > 0, such that for all N >= n0, A. f(N) <= c2g(N) B. f(N) >= c1g(N) C. c1g(N) <= f(N) <= c2g(N)

C g(N) is both the upper and lower bound of f(N).

T/F In probing, it is possible that >= 2 data entries are stored in one row of the hash table.

False Probing strategy stores at most one data entry per row in the hash table.

In our IntVector class, of the constructors and assignment operator= in the Big Five, which do NOT require a deep copy? Here deep copy means copying the data that the pointer arr is pointing at instead of copying arr itself. A. Copy constructor B. Copy assignment operator= C. Move constructor D. Move assignment operator=

C, D The copy constructor and copy assignment operator= require deep copy. Even though copy assignment operator= can be implemented by "copy and swap" idiom, the "copy" step runs copy constructor, thus it still requires deep copy. Move constructor and move assignment operator= do not require deep copy. In fact, they only deal with the pointer itself. Move constructor assigns rhs' arr to arr. Then it null out rhs' arr. Move assignment operator= swaps rhs' arr and arr, thus only swapping the address of the data that rhs' arr is pointing at, and the address of the data that the calling object's arr is pointing at.

Suppose we already initialized objects X and Y which are both of class IntCell, and suppose class IntCell has operator+ overloaded. Which of the following Big-Five will be called for this line of code: X = Y + 13? A. Copy constructor B. Copy assignment operator= C. Move constructor D. Move assignment operator=

D It is move assignment because 1) X already existed before calling this line of code, thus the answer should be an assignment not a constructor; 2) The rhs is an R-value (it does not have a name), thus the answer is the move assignment operator= not the copy assignment operator=.

What is the complexity of the following code? while(N > 1) N = N/2; A. O(N^2) B. O(NlogN) C. O(N) D. O(logN)

D The complexity is O(logN) because each loop cuts N by half. Thus after int(logN) + 1 loops, N will be <= 1, and the algorithm will quit out of the while loop. Thus no more operations will be done afterwards. The key to answer this question is to calculate how many loop there are. Note that logN may not be an integer number, but Big O notation does not care the constant that has to be added to obtain the exact number of loops to get N to <= 1 because we only care about the highest order which is logN.

In the following tree structure, what is the depth of node C? What is the height of node C? What is the height of the tree? A / | \ B E G | | C F | D

Depth of C: 2 Height of C: 1 Height of the tree: 3 C's depth is 2 because the path length from the root to C is 2 (2 edges are involved). C's height is 1 because the length of the longest path from C to one of its descendants is 1 (from C to D, 1 edge is involved). The tree's height is root's height, which is 3.

T/F The following usage of "explicit" keyword is legitimate. explicit IntCell() {}

False "explicit" shall be used only for the one parameter constructor, not zero parameter constructor.

T/F Is the following a complete binary tree? A / \ B D / \ C E

False A complete binary tree has all the levels above the bottom level populated, and all the nodes on the bottom level are at the leftmost position. There are two spots on the bottom level that should have been populated before E populates the right child of D, which are, right child of B and left child of D. Thus this is not a complete binary tree.

T/F As we know, the maximum element of the tree is on the rightmost of a BST. The following code aims to find a BinaryNode that has the maximum element of the subtree rooted by t using a recursive function. Is it a correct implementation? BinaryNode * findMax( BinaryNode *t ) const { if( t->right == nullptr ) return t; return findMax(t->right) }

False It does not consider the case when the given node t is a nullptr.

T/F Suppose in the main function, we want to use std::initializer_list function template to construct i1 to be {1, 2, 3, 4}. Is the following legitimate? #include <initializer_list> using std::initializer_list; int main() { initializer_list i1{ 1, 2, 3, 4 }; return 1; }

False It is not legitimate because initializer_list is a function template. We have to add the type such as int to instantiate an object. This code is legitimate: initializer_list<int> i1{ 1, 2, 3, 4 };

T/F In Q1, is the following declaration of object a1 valid? MemoryCell a1;

False It's not valid because MemoryCell is a template class, not a class. It cannot be used to declare an object directly.

T/F Do member initializer list and std::intializer_list refer to the same thing?

False Member initializer list is a way of assigning values to the data members in the constructor of a class. std::initializer_list is a template class.

T/F In Q1, is MemoryCell a class?

False MemoryCell is not a class, but a class template.

T/F For the Doubly Linked List covered in textbook Sec. 3.5 (also in Module 5.2 and Module 6), there is a nested class const_iterator inside the container class template List<Object>. Suppose inside this const_iterator class, there is no "friend" line that claims the List<Object> as const_iterator's friend class. Can the List<Object> class template's functions directly use "current", the protected data member of const_iterator?

False The enclosing class (List<Object>) cannot access the nested class's non-public data member unless the nested class claims that the enclosing class is its friend.

T/F Suppose we declared and defined only one version of Func which is void Func(int &x) . Is it legitimate to have this function call: Func(x + 5)?

False This Func signature is pass by L-value reference, which cannot take an R-value as the input because pass by L-value reference is supposed to be able to change the original variable, but an R-value, which is the input, cannot be changed.

T/F In our IntVector example, suppose we put interface of the IntVector class in a .h file, and all implementations including nonclass functions in a .cpp file. The following is the right implementation of a nonclass function in the .cpp file that pipe the elements in v of type IntVector to os of type ostream, and return a reference to os for cascading, supposing this function has been declared "friend" in IntVector class. Hint: check the scope of the function. ostream& IntVector::operator<< (ostream& os, const IntVector& v) { if (v.size == 0) return os << "Empty vector"; // otherwise os << "{" << v.arr[0]; for (int i = 1; i < v.size; i++) os << ", " << v.arr[i]; return os << "}"; }

False This implementation is not correct because function ostream & operator<< (ostream&, const IntVector&) is not a function inside IntVector class. It is a nonclass function declared as a friend to IntVector class. Thus the scope shall not be IntVector::. The correct implementation thus shall not have IntVector:: in the first line. It is still appropriate to put the implementation of this nonclass function in intvect.cpp file together with other class functions though.

T/F All binary trees can be effectively represented by a vector, i.e., given parent node's index, we can calculate child nodes' indices, vice versa.

False This is wrong. Only a specific type of binary tree, called complete binary tree, can be effectively represented by a vector.

T/F Suppose our IntVector class does NOT claim the following nonclass function ostream& operator<< (ostream& os, const IntVector& v); as its friend. Can we use the following code to define this function? ostream& operator<< (ostream& os, const IntVector& v) { if (v.size == 0) return os << "Empty vector"; os << "{" << v.arr[0]; for (int i = 1; i < v.size; i++) os << ", " << v.arr[i]; return os << "}"; }

False We cannot because the nonclass function cannot access the private data member directly ( such as using v.arr[i] ) when it's not claim as a friend of the class. In this case to do what this nonclass function is supposed to do, we have to write a public accessor function in IntVector class such as v.get(i) in place of v.arr[i].

T/F In Q1, is it possible to put the implementation of the template class in memorycell.cpp, in which we "#include meorycell.h" file, and use "g++ -std=c++11 -c memorycell.cpp" to ask the compiler to generate a memorycell.o file?

False We cannot do this because the compiler does not know what the type "T" is (and thus cannot assign the space for T) before we declare an actual object. The compiler will report an error.

Which of the following is the return type of front() and back() in List implementation in Sec. 3.5 (Module 5.2 and 6)? a. Object (the generic type for the data) b. const_iterator c. iterator d. Node * (a pointer to a Node)

a The return type of front() and back() is the type of the data, which is Object the generic type.

T/F Is the following tree a BST? 11 / \ 9 13 / \ / \ 9 10 12 14 / \ 4 7

True A binary tree B is a BST if 1. There is an order relation <= defined for the vertices of B; 2. For any vertex v, all vertices on the left subtree of v are <= v, and v <= all vertices on the right subtree of v.

T/F Is the following tree a binary tree? A / \ B D / \ C E

True A binary tree does not have any node whose child node number is >= 3. Since none of the nodes in this tree has >= 3 child nodes, this is a binary tree.

T/F In Q1, is the following declaration of object a2 valid? MemoryCell<int> a2;

True Because MemoryCell<int> is a class, we can use it declare an object.

T/F In IntVector class, if we use the "copy and swap" idiom shown in the code below to define the copy assignment operator= function, we want to make sure that the IntVector class has the copy constructor, move constructor and move assignment operator= appropriately defined. IntVector& IntVector::operator=(const IntVector& v) { if (this != &v) { IntVector copy = v; std::swap(*this, copy); } return *this; }

True Copy and swap idiom needs a. copy constructor appropriately defined due to the "copy" step (IntVector copy = v;) b. move constructor and move assignment operator= appropriately defined due to the "swap" step (std::swap(*this, copy);)

T/F Suppose we want to write a copy assignment operator= function for the class IntVector, and the following is the function signature: IntVector & operator=(const IntVector & v); Suppose our implementation is first delete the data that the arr is pointing at, followed by member by member assignment. Is it necessary to first check whether v is not the same as the calling object using the following if statement: if (this != &v)

True In copy assignment operator= function, if the implementation is member by member assignment after deleting the data that the pointer is pointing at, we need to first check whether the rhs object is the calling object. If we don't do that, suppose rhs object v is the same as the calling object. Since v is passed by const reference, we cannot change v. But when we delete the data of the calling object, we are actually deleting the data of v, which cannot be changed, leading to compilation complaint. To avoid that, we check whether rhs' address is the same as the calling object's address first, the latter of which is indicated by this.

T/F To use std::initializer_list function template, is it necessary to #include <initializer_list>?

True It is necessary to #include <initializer_list> to use std::initializer_list.

T/F In Q1, is MemoryCell<int> a class?

True MemoryCell is not a class, but a class template. MemoryCell<int> is a class.

T/F With the following code: explicit IntCell( int initialValue = 0 ) : storedValue{ initialValue } { } The automatic type conversion such as: IntCell obj = 37; is illegitimate.

True Since 37 is an integer, whereas obj is an IntCell, an automatic type conversion is needed. However, using "explicit" disallows the automatic type conversion. Thus it is illegitimate.

T/F Suppose an object i1 is of type initializer_list<int> and has been declared and initialized in the following way: initializer_list<int> i1{ 1, 2, 3, 4 }; Is it legitimate to use the following for loop to navigate every element in i1? for(auto x : i1) {// do something }

True Since std::initializer_list has the iterator implemented internally, this for loop is legitimate.

T/F For the same condition of Q4, i.e., there is no "friend" line that claims that List<Object> is const_iterator's friend. Can the const_iterator class' functions directly use the private data members such as head and tail of the List<Object> class template?

True The nested class (const_iterator) can always access enclosing class' data members, even if they are private. This is unrelated with whether the nested class claims the enclosing class as its friend. Thus the functions inside the nested class can access the same range of data members as the functions in the enclosing class.

T/F Suppose we declared and defined only one version of Func which is void Func(int x). Is it legitimate to have this function call: Func(x + 5)?

True This Func signature is call by value. A local copy will be made for the R-value x + 5 and thus is legitimate.

T/F Suppose we declared and defined only one version of Func which is void Func(int && x) . Is it legitimate to have this function call: Func(x + 5)?

True This Func signature is pass by R-value reference, which takes an R-value such as x + 5.

T/F Suppose we declared and defined only one version of Func which is void Func(const int & x). Is it legitimate to have this function call: Func(x + 5)?

True This Func signature is pass by const reference, which takes an R-value such as x + 5. Thus is legitimate.

T/F The major advantage of using a hash table is its fast search, insertion and deletion.

True This is a true statement. A hash function takes O(1) time. Although both separate chaining and probing take some time to locate exactly where the item is, as long as the entries are evenly distributed on the hash table, and the hash table is not very full, hash table's search, insertion and deletion are the fastest among data structures compared with vector, list, and BST.

T/F If a data set requires a lot of findMin, findMax and sort, hash table is not a good data structure to store this data set.

True This is a true statement. Hash table does not sort the data entries at all. Thus it takes O(n) to findMin and findMax. sort takes even more time than linear. Thus it is not recommended to use hash table if there are a lot of such operations required on the data.

T/F Typically the TableSize of a hash table is a prime number to encourage even distribution of the data entries throughout the whole table.

True This is a true statement. Prime number as the table size helps to evenly distribute the data entries on the hash table.

T/F For a particular f(N) representing the estimated running time of an algorithm in which N is the input size, it is possible to have multiple upper bounds and multiple lower bounds.

True This is correct. If we do not require the tightest upper bound or the tightest lower bound, there could be multiple upper bounds and multiple lower bounds. For example, f(N) = 3N^2 + 17 has Ω(1), Ω(N), Ω(N^2) as lower bounds, and O(N^2), O(N^3), ... as upper bounds.

T/F When we insert a BinaryNode to a BST that has never been existing on the tree, the newly inserted BinaryNode will be on a leaf.

True This is correct. When we traverse the tree to find the position to insert the element, we go to the left or the right subtree depending on whether the inserted element is smaller than or larger than our current node's value. When at a point we cannot go any further, i.e., there is no left or right subtree to go, we add a node attaching to the current node that does not have the left or right subtree. Thus such an element will be attached as a leaf node.

T/F For the intvector class that we discussed in the last lecture, the main reason that we have both size and capacity as the data members of the class is that we want to avoid allocating new space followed by a copy every time we insert an item to the dynamic array.

True This is true because capacity is always >= size. And capacity is the allocated array size, whereas size is the number of elements inside the array. Suppose we have capacity=5 and size=3. We do not have to increase the capacity of our array (which is expensive since we have to allocate new space, copy every element to the new space, and deallocate the current space) for another two inserts. capacity gives us the buffer to avoid this series of expensive operations for every insert.

T/F To use priority queue structure in C++ STL, we should #include <queue>, suppose using namespace std has also been included.

True This is true. Both priority queue and queue can be used when we #include <queue>.

T/F For a heap data structure, if we delete an element, we delete either the maximum or minimum element instead of any element.

True This statement is correct. We either deleteMin() in a minHeap, or deleteMax() in a maxHeap. This is different from a Queue structure, which deletes the first-in element in the queue.

T/F When we use g++ command for compilation and linking, if we really want to make sure that the compiler's version is c++11, it is appropriate to add "-std=c++11" in the g++ command. For example, if we want to generate an object file main.o from main.cpp, the following command is appropriate. main.o: g++ -std=c++11 -c main.cpp

True We need to add the tag "-std=c++11" to make sure the correct version of compiler is used for both compilation and linking.

T/F In DFS (depth-first search) algorithm using the stack, when an element is at the top of the stack, we push to the stack this element's one unvisited neighbor to the stack. If there are multiple unvisited neighbors of this element, we push to the stack this element's one unvisited neighbor to the stack every time when this element is at the top of the stack.

True We push only one unvisited neighbor because DFS processes only one neighbor for each time when the node is at the top of the stack. If there are multiple unvisited neighbors, the other unvisited neighbors will be pushed one at a time when this element is exposed (on the top of the stack). Notice that this element will be exposed multiple times when all other elements are popped. Each time when this element is at the top of the stack, an unvisited neighbor can be pushed to the stack.

Of the following tree structure, what is the sequence of the nodes from a levelorder traversal? a. A, B, E, G, C, F, D b. A, B, C, D, E, F, G c. D, C, B, F, E, G, A d. D, C, F, B, E, G, A A / | \ B E G | | C F | D

a Levelorder traversal is queue-based, and once the node is pushed to the queue, it is marked as visited. All child nodes will be pushed to the queue one by one all together when the parent node is at the top of the queue.

What is the feature of queue? a. FIFO (first in first out) b. LIFO (last in first out)

a Queue's feature is first in first out.

For the Vector container and Doubly Linked List container mentioned in Q1 and Q2, respectively, which of the following do both of them have O(N) algorithm complexity with? a. Erase a range of elements whose begin and end positions are specified by two iterators; b. Erase an element at a location specified by an iterator; c. Find an element whose value is the same as a given value; d. Copy constructor that initializes the data value of every element.

a, c, d a and c take O(N) time because we always assume the worst-case scenario. Thus for a, it's possible that from the very beginning to the very end of the container, all elements shall be erased. For c, it's possible that there is no such element with the given value. And thus all elements in the container to be navigated through. d is also O(N) because the assignment of the values for each element has to be done one by one. b is O(1) for Doubly Linked List, thus is not selected.

Which of the followings are R-values? a. 5 in "x = 5" b. x in "int x" c. y + 3 in "z = y + 3" d. y in "z = y + 3" e. 3 in "z = y + 3" f. z in "z = y + 3"

a, c, e Generally, R-values are those temporary values that do not have a name. Here, "5", "y + 3", and "3" do not have a name, and thus they are R-values. "x", "y" and "z" have a name, thus they are L-values.

For the Vector container implementation in textbook Sec. 3.4 (also covered in Module 4), which of the followings have O(1) algorithm complexity? a. Getting the value of the ith element in the dynamic array; b. Insert an element at a location specified by an iterator; c. Erase an element at a location specified by an iterator; d. Destructor which cleans up the whole array.

a, d Getting the value at the ith position has O(1) complexity because the dynamic array has all elements stored in a contiguous memory. The destructor has O(1) complexity because it can delete the memory that the dynamic array has all at once due to that all elements are stored in a contiguous memory. Insert and erase take O(n) time for the Vector, because for insert, all elements after and including the position to be inserted have to be move further down to make space for the new element to be inserted; for erase, all elements after the position to be erased have to be moved up so that there is no vacancy in the dynamic array.

Fill in the blanks in the code. ------- inside memorycell.hpp ------ blank1 blank2MemoryCell(const T& initialValue): storedValue{initialValue} {} ------- end of inside memorycell.hpp ------ ------- begin of memorycell.h ------ #ifndef memorycell_h #define memorycell_h template <typename T>class MemoryCell { public: explicit MemoryCell(const T& initialValue = T{}); const T& read() const; void write(const T& x); private: T storedValue; }; #include memorycell.hpp #endif ------- end of memorycell.h ------

blank1: template <typename T> blank2: MemoryCell<T>::

Of the following tree structure, what is the sequence of the nodes from an inorder traversal? a. A, B, C, D, E b. A, B, D, C, E c. C, B, A, D, E d. C, B, E, D, A A / \ B D / \ C E

c Inorder traversal takes care of the left subtree, then the node itself, then the right subtree.

Of the following tree structure, what is the sequence of the nodes from a postorder traversal? a. A, B, E, G, C, F, D b. A, B, C, D, E, F, G c. D, C, B, F, E, G, A d. D, C, F, B, E, G, A A / | \ B E G | | C F | D

c Postorder traversal is depth-first search, but it is visit on departure (child-first). Thus it's only when all children are visited that the parent will be marked as visited.

Which of the followings are legitimate? a. int & x = 3 + 5; b. string & a = "hello"; c. string && a = "hello"; d. y = 3 + 5; int & x = y;

c, d && is used for defining an R-value reference, and can reference R-values. & is used for defining an L-value reference, and can only reference L-values, not R-values. In a and b, since 3+5, "hello" are R-values, L-value reference does not work. Thus a and b are illegitimate. In c, we use an R-value reference to reference an R-value, which is legitimate. In d, y is an L-value. We use an L-value reference to reference an L-value, which is legitimate.

Of the following tree structure, what is the sequence of the nodes from a preorder traversal? a. A, B, E, G, C, F, D b. A, B, C, D, E, F, G c. D, C, B, F, E, G, A d. D, C, F, B, E, G, A A / | \ B E G | | C F | D

b Preorder traversal is depth-first search, but it is visit on arrival (parent-first). Thus once parent is pushed to the stack, the parent is marked as visited.

What is the feature of stack? a. FIFO (first in first out) b. LIFO (last in first out)

b Stack's feature is last in first out.

When we apply the algorithm of converting an infix to a postfix expression, suppose our infix expression is 6 + 10 * 2 / 3 - ( 11 - 1 ) Which of the following (choose one from a-e) is the first operator popped from the stack? This question supposes the following rule of precedence among the operators. 1. * (multiplication) and / (division) have the same precedence; 2. + (plus) and - (minus) have the same precedence; 3. * (multiplication) and / (division) have a higher precedence than + (plus) and - (minus). 4. The precedence is left-associative, which means if two operators have the same precedence and are neighbors, then the left one has a higher precedence. a. + b. * c. / d. - e. (

b When we encounter / (division), the stack has + (plus) and * (multiplication), whereas * (multiplication) is on the top of the stack. Since * (multiplication) and / (division) has the same precedence, and the order is left-associative, * (multiplication) has a higher precedence than / (division). Thus we pop * (multiplication) first, and then push / (division) in. Thus the * (multiplication) was the first operator popped from the stack.

For the doubly linked List container implementation in textbook Sec. 3.5 (also covered in Module 5.2 and Module 6), which of the following have O(1) algorithm complexity? a. Getting the value of the ith element in the list; b. Insert an element at a location specified by an iterator; c. Erase an element at a location specified by an iterator; d. Destructor which cleans up all elements in the list.

b, c For the List implementation, unlike Vector, accessing the ith element take O(N) time because the elements are not stored in contiguous memory. The destructor also takes O(N) time because since the elements are not stored in contiguous memory, we have to delete each element one by one. Both insert and erase in List take O(1) time because what they mainly do is to add/modify prev and next in the current, previous and next nodes.

Which of the following are the return type(s) of begin() and end() in List implementation in Sec. 3.5 (Module 5.2 and 6)? a. Object (the generic type for the data) b. const_iterator c. iterator d. Note * (a pointer to a Node)

b, c The return types for begin() and end() functions are const_iterator and iterator.

Fill in the blanks in the code. class FunctorSum { public: int blank1(int a, int b) { return blank2; } };

blank1: operator() blank2: a+b

For Q2's postfix expression: 1 2 4 + 5 * 15 / + While running the 2nd algorithm (Evaluating Postfix Expression) taught in the Stack lectures, what is the fourth element that will be inserted to the stack? a. 1 b. 2 c. 4 d. 6 e. 5

d It's 6 because 1, 2 and 4 got into the stack. Then we encounter "+", which pops 2 and 4. We then evaluate (2+4), which is 6. We thus push 6 to the stack, which is the 4th element pushed to the stack.

Given the following code, suppose we have a vector<int> type data called list1. Write one line of code to print only the odd elements in list1: template <typename C> void print(vector<int> array, C cond) { for (auto i : array) if ( cond(i) ) cout << array[i]; } class IsNeg{ public: bool operator() (int x) { return (x < 0); } }; class IsOdd{ public: bool operator() (int x) { return (x % 2 != 0); } };

print(list1,IsOdd());


Related study sets

Chapter 2 Quiz - Policy Provisions and Contract Law

View Set

Ch.6, Lesson1: The Revolution Begins

View Set

Witness Questions Eugene V. Debs

View Set

Mental Health Chapters 11-19 pre and post tests and NCLEX questions

View Set

A&P Chapter 16 and 17 Test Questions

View Set

accommodated unit 2 science test

View Set

Common Viral Infections: Characteristic Signs and Symptoms

View Set

Occupational Safety and Health Administration

View Set