Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

NATIONAL UNIVERSITY OF SINGAPORE

SCHOOL OF COMPUTING
SEMESTER II AY2010/2011

CG1103: DATA STRUCTURES AND ALGORITHMS I


Mid Term Test Time Allowed: 1 hour 30 minutes

MATRICULATION NUMBER:

INSTRUCTIONS TO CANDIDATES:

1. Write your matriculation number in the space provided above. Also write your
matriculation number at the top of each sheet in the test paper. Shade your
matriculation number on the OCR form. Remember to sign on the form.

2. This examination paper consists of FOUR (4) questions. Question 1 consists of 10


MCQ questions.

3. This examination paper comprises TWELVE (12) printed pages including this front
page.

4. Answer the MCQ questions by shading the OCR form and answer all of the other
questions directly in the space given after each question. You are allowed to answer
in PENCIL.

5. Marks allocated to each question are indicated. Total marks for the paper is 100.

6. This is a CLOSE BOOK test. You are allowed to bring in ONE (1) piece of A4
handwritten reference sheet. No photocopies allowed.

EXAMINER’S USE ONLY


Questions Possible Marks Grader Check
MCQ 1- 10 50
Question 2 24
Question 3 10
Question 4 16
Total 100

1
MCQ ( 10 * 5 Marks = 50 Marks)

1. Which of the following statement regarding visibility (accessibility) is TRUE?

a. It is syntactically incorrect (i.e. results in compilation error) if an object


attribute is declared as public.
b. All object attributes are inherited by a subclass regardless visibility.
c. Methods cannot have protected visibility.
d. If a method is declared as private, then it cannot be invoked even by other
method of the same class.
e. None of the above.

2. What is the output for the following code fragment?


void swapPointers(int* ipA, int* ipB)
{
int* temp;

temp = ipA;
ipA = ipB;
ipB = temp;
}

int main()
{
int i = 123, j = 456;

swapPointers( &i, &j );

cout << i << "," << j << endl;


return 0;
}

a). 123, 456


b) 123, 123
c) 456, 456
d) 456, 123
e) The code results in runtime error (segmentation fault)

3. Which of the following statement regarding List ADT is TRUE?

a. The logic of insertion/deletion/retrieval is affected by the type of items stored


in List.
b. List ADT cannot be implemented by a vector.
c. If we use dynamic array to implement List ADT, then it can have
unrestricted size (up to the memory capacity).
d. Using only insert(), remove() or retrieve(), it is impossible for us
to locate the largest item stored in a List ADT.
e. None of the above.

2
4. Suppose we have a function with the following header:
void funcOne( SomeClass& obj);

which of the following comment(s) is/are TRUE?

i. funcOne() function can potentially modify the actual argument


passed in as the parameter.
ii. The "obj" is a pointer to an object of the SomeClass type.
iii. Invoking funcOne() function will result in constructing a new object
obj of the SomeClass type.

a. (i) only.
b. (i) and (ii) only.
c. (ii) and (iii) only.
d. (i) and (iii) only.
e. (i), (ii) and (iii).

5. Given the following template function:

template <typename T>


int mysterious( T array[], int size, T target)
{
int count = 0;
for ( int k = 0; k < size; k++)
if ( array[k] == target )
count++;
return count;
}

What is the result for the following code fragment?

int iA[6] = { 3, 1, 0, 3, 1, 1};


cout << mysterious<int>( iA, 6, 3 ) << endl;

string sA[6] = { "no", "no", "yes", "no", "yes", "no"};


cout << mysterious<string>( sA, 6, "yes" ) << endl;

a. 0
0
b. 2
2
c. 4
4
d. 2
4
e. 2
undefined (some random values)

3
6. Using the same template function in Q5, what is the result of the following code
fragment?

int i, j, k;

i = 123;
j = 123;
k = 246;

int* ipA[6] = { &i, &j, &i, &k, &i, &j };


//ipA is an array of integer pointers

cout << mysterious<int*>( ipA, 6, &j );

a. 2
b. 4
c. 5
d. 6
e. address of variable "j" is printed

7. In our course, we use the following statement in order to make use of an ADT:

ADT_Base* ptr = new Actual_ADT_Implementation;


ptr-> method();

For example:
ListBase* listPtr = new ListArray;
listPtr->insert( 1, 123 );

Which of the following mechanism(s) is/are essential for the above design /
organization to work properly?

i. Subclass substitution principle


ii. Dynamic binding of method
iii. Abstract class

a. (i) only.
b. (i) and (ii) only.
c. (ii) and (iii) only.
d. (i) and (iii) only.
e. (i), (ii) and (iii).

4
8. Given the two different approaches to read in 3 integers below:

Approach A:

int a, b, c;
cin >> a;
cin >> b;
cin >> c;

Approach B:

int a, b, c;
string input;
getline( cin, input );

istringstream iss( input );


iss >> a;
iss >> b;
iss >> c;

Suppose 3 different users X, Y and Z keyed in the input differently:


User X:
123 456 789

User Y:
123
<empty line>
456
789

User Z:
123<tab>456<tab>789 //<tab> refers to the tab key

Which of the following statement is true regarding the behavior?

a. Approach A can handle only User X, Z but not user Y.


b. Approach B can handle only User X, Z but not user Y.
c. Approach A can handle only User X, but not user Y or Z.
d. Approach B can handle only User X, but not user Y or Z.
e. Both approaches can handle all three users.

9. Which of the following regarding ADT is TRUE?

a. ADT is the set of built in data types of a programming language


b. An ADT can have only one implementation
c. All implementations of an ADT support the same set of methods in the
specification.
d. In C++, the idea of ADT must be implemented through abstract class
e. None of the above

5
10. Below is the Pair template class discussed in lecture:

template <typename T1, typename T2>


class Pair {
private:
T1 _first; //first value
T2 _second; //second value

public:
Pair(T1 a, T2 b) : _first(a), _second(b) {}

T1 getFirst() const { return _first; }


T2 getSecond() const { return _second; }
};

Given the following code fragment:

Pair<string, int> p1( "P1", 1234.5 );


Pair<double, string> p2( 1234.5, "P2" );

cout << p1.getFirst() + p2.getSecond() << endl;


cout << p1.getSecond() + p2.getFirst() << endl;

Which of the following is the correct behavior?

a. The code will output:


P1P2
2469.0

b. The code will output:


P3
2469.0

c. The code will output:


P1P2
2469

d. The code will output:


P1P2
2468.5

e. None of the above

11. (Bonus) Who is the designer of the C++ language?

a. Alan Turing
b. Ken Thompson and Dennis Ritchie
c. Bjarne Stroustrap
d. James Gosling
e. Uncle Soo

6
Short Question ( 50 marks)

Question 2 ( 24 marks)

(Part I – 12 marks) Given an integer singly linked list, for example:

head
next

1 1 1 2 1 1

We'd like to "compact" the linked list by removing adjacent nodes with the same
value. For example, the above linked list can be compacted to:

head next

1 2 1

Below are a few more examples to aid your understanding.

Original Linked List After compaction


1 1  1  2  1  1 1 2  1
(This is the same as the example shown above)
3 3 2  2  1  1 3 2  1
3 3 3  3  3  3 3
1 2  3  4 1 2  3  4
(no change as there is no duplicate)
<empty> <empty>

Give a C++ function to perform the compaction as described. Write your code in the
box provided in the next page.

You can assume that each linked list node is declared as follows:

struct ListNode {
int item;
ListNode* next;
};

7
void compact( ListNode* head )
//Pre-condition: None
//Post-condition: Linked List starting from "head" is compacted
// as described in the question
{

ListNode *cur, *temp;

cur = head;

while (cur != NULL && c->next != NULL ){


//The ordering of the conditions above is important

if (cur->item == cur->next->item){
temp = cur->next;
cur->next = cur->next->next;
delete temp;
} else {
cur = cur->next;
}
}

//Important checks:
- Handles empty or 1 node list correctly?
- Any segmentation fault? e.g. ptr->item when ptr
may be NULL?
- Is "delete" used?

8
(Part II – 12 marks) Suppose we want to "expand" a given linked list with the
following rules:
 For every node N in the linked list, the item stored (which is a positive integer)
is retrieved. Let's call the item X.
o The node N will then be duplicated X times and inserted after node N.
e.g. If a node stores the value "5", the node will be duplicated 5 times.
 Note that the nodes duplicated are ignored in subsequent processing.

Below are some examples. The nodes duplicated are shown in bold.

Original Linked List After expansion


1 1  2 1 1 1  1  2  2  2
3 3 3  3  3
22 2  2  2 2  2  2
<empty> <empty>

You can assume that the item stored in each linked list node is a positive integer.

void expand( ListNode* head )


//Pre-condition: None
//Post-condition: Linked List starting from "head" is expanded
// as described in the question
{

ListNode *cur, *newNode;


int times;

cur = head;
while ( cur != NULL ){
times = cur->item;
//Duplicate "times" number of nodes
for (int i = 0; i < times; i++){
newNode = new ListNode;

newNode->item = times;
newNode->next = cur->next;
cur->next = newNode;

//Move cur to make it easier for insertion


cur = cur->next;
}
//One more time to skip over processed node
cur = cur->next;
}

//Important checks:
- Handles empty or 1 node list correctly?
- Create and link up new nodes correctly?
- Skip processed nodes correctly?

9
Question 3 ( 10 marks)

Given a string S, and a shorter non-empty string T, we would like to count the number of
occurrences of T in S.

String S String T Number of Occurrences


"ababab" "ab" 3
"ababaaab" "ab" 3
"aaaaa" "aaa" 3
"aaaaa"
"aaaaa"
"aaaaa"
"" "aa" 0

Write a function to perform the above. You are only allowed to use the following predefined
string methods and simple indexing to help:

int length();
//return the number of characters in string

string substr( int idx, int len );


//return a substring of length len starting at index. Only up to the end of string will be returned
// if len is larger than the remaining length of the string.
//e.g. string s = "1234567890"; s.substring( 0, 4 )  "1234"
//e.g. string s = "1234567890"; s.usbstring( 7, 10 )  "890"
int countSubStr( string s, string t )
//Pre-condition: String t is an non-empty string that is shorter
// than string s
//Post-condition: Number of occurrences of substring t in s is
// returned
{

int count = 0;

for(int idx = 0;
idx <= s.length() – t.length(); idx++) {
if (s.substr( idx, t.length()) == t )
count++;
}

return count;

//Important checks:
- Terminate as early as possible?
- Extract and compare correctly?

10
Question 4 ( 16 marks )

Given the following three classes:

class A
{
public:
void M1() { cout << "A.M1\n"; }
virtual void M2() { cout << "A.M2\n"; }
void M3() {
this->M1();
this->M2();
}
};

class B: public A
{
public:
virtual void M2() { cout << "B.M2\n"; }
};

class C: public B
{
public:
void M1() { cout << "C.M1\n"; }
};

For each of the code fragment shown on next page, indicate whether:
 The code will cause compilation error. Briefly explain the reason. OR
 The code can compiles and execute. Supply the execution result in this case.
Note that any code fragment with both choices filled will be taken as incorrect. Each
code fragment should be considered on its own, independent from other code
fragments. See below for two simple examples.

Code Fragment Compilation Error Execution Result


A* a = new A; A.M1
a->M1();

A* a = new A; Method M4() not defined in


a->M4(); class A

11
Code Fragment Compilation Error Execution Result
A* a = new B; A.M1
a->M1(); M1 is statically
binded.
A* a = new C; A.M1
a->M1(); M1 is statically
binded.
B* b = new A; Violate subclass substitution.
b->M2(); B is not a superclass of A.

A* a = new C; B.M2
a->M2(); M2 is dynamically
binded. The latest
implementation is in
B.
A* a = new B; B.M2
a->M2(); M2 is dynamically
binded. The latest
implementation is in
B.
A* a = new C; A.M1
a->M3(); B.M2

A* a = new B; A.M1
a->M3(); B.M2

B* b = new B; A.M1
b->M1(); Inherited from A

~~~~~End of Paper + Good Luck ~~~~

12

You might also like