Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 23

Hong Kong University of Science and Technology COMP104: Programming Fundamentals and Methodology

Fall 2004, Lecture Section 1, 2, 3 Final Examination Friday, Dec.17, 2004 08:30 11:30AM Student Name: Student ID: Instructions: This is a closed-book, closed-notes examination, calculator is also not allowed. Check that you have all 21 pages (including this cover page). Write your name, student ID, lecture section, lab section and TA name on this page. Please circle your answer. 5. Answer all questions in the space provided. Rough work should be done on the back pages.
1. 2. 3. 4.

key

Lecture Section: Lab Section/TA Name:

Question 1 2 3 4 5 6 7 8 Total Strings File I/O Pointers

Topic /10 /5 /9 /10 /14 /18 /10 /24 /100 /100

Score

Simple Linked List Algorithms on Linked List Doubly Linked List Classes Dynamic Classes/ADT

Question 1 : Strings (10 marks)


a) What is the output of the following program? (1 mark)
#include <iostream> #include <string> using namespace std; void main(){ string x = "2"; string y = "3"; string z = "5"; if(x+y == z){ cout << "2 + 3 = 5" << endl; } else{ cout << "2 + 3 != 5" << endl; } }

Answer (1 mark): 2 + 3 != 5

b) What is the output of the following program? (2 marks)


#include <iostream> #include <string> using namespace std; void main(){ string x = "4"; string y = "2"; string sum = x + y; cout << sum << endl; }

Answer (2 marks, 1 for each digit): 42

c) Complete the following program to print the users input word in reverse order and check if it is a palindrome. A word is a palindrome if its reversion is the same as itself. For example, the output of the program should look like this: Enter a word to reverse: canoe Your word spelled backwards is: eonac It is not a palindrome. Or Enter a word to reverse: kayak Your word spelled backwards is: kayak It is a palindrome. Also, it should be case sensitive, i.e., kayak is a palindrome, but Kayak is not. You can use predefined C++ string functions such as xxx.length() (this function returns the number of characters of the given string xxx). (7 marks)
void main(){ string inword, outword; bool isPalindrome; // Get user input cout << "Enter a word to reverse: "; cin >> inword; // copy user input into outword, this will make sure // outword is long enough to contain inword outword = inword; // START YOUR CODE HERE ----->

// <---END YOUR CODE HERE // Output the reversed word and whether it's a palindrome cout << "Your word spelled backward is: " << outword << endl; if(isPalindrome) cout << "It is a palindrome" << endl; else cout << "It is not a palindrome" << endl; }

Answer (7 marks): for(int i=0; i<inword.length(); i++)

// 2 marks
3

outword[inword.length() - i - 1] = inword[i]; // 3 marks if(outword == inword) // 2 mark isPalindrome = true; else isPalindrome = false;

Question 2: File I/O (5 marks)


Suppose file test.dat contains 3 integers separated by spaces. For example: 23 35 60 Write C++ code to open the file, read in 3 integers from the file, and display them on the screen in reverse order separated by spaces. For the above file, the output of your program should be: 60 35 23
#include <iostream> #include <fstream> using namespace std; void main(void){ // START YOUR CODE HERE ----->

// <---}

END YOUR CODE HERE

Answer (5 marks): int n1, n2, n3; ifstream fin; fin.open(test.dat); // 1 mark // 1mark

fin >> n1; fin >> n2 ; fin>> n3 ;

// 1 mark

cout << n3 << << n2 << << n1 << endl ; fin.close() ;

// 1 mark // 1 mark

Question 3: Pointers (9 marks)


a) Given the following lines of codes,
int ival = 1024; int ival2 = 2048; int* pi1 = &ival; int* pi2 = &ival2; int** pi3 = 0;

Are the following statements legal or illegal? (3 marks)


(1) pi2 = *pi1; (2) ival = pi1; (3) pi3 = &pi2;

Answer(3 marks, 1 for each):


(1) illegal (2) illegal (3) legal

b) What is the output of the following program? (6 marks)


#include <iostream> using namespace std; int x,y; void Fun1(int* a,int* b,int* c){ *a=*b+x; *b=*c+y; } void Fun2(int a,int b,int c){ a=b+x; b=c+y; } void Fun3(int& a,int& b,int& c){ a=b+x; b=c+y; } void main() { x=10,y=15; Fun1(&y,&x,&y); Cout << x << " " << y << endl; Fun2(y,x,y); cout<< x << " " << y << endl; Fun3(y,x,y); cout<< x << " " << y << endl; }

Answer(6 marks, 1 each):


40 20 40 20 160 80

Question 4: Simple Linked List (10 marks)


Identify and fix the bugs. Given the following definitions of Node and NodePtr:
struct Node { int data; Node* next; }; typedef Node* NodePtr;

The following function is supposed to delete multiple elements from an unsorted simple linked list which contains only positive integers. Given a key element k(a positive integer), the function searches and deletes all its multiples that are greater than itself. (i.e. nk, n>=2). The input parameter Head points to the first element of the linked list and delkey is the key element whose multiples are to be deleted. There are FIVE mistakes in the following implementation. Please identify and fix them all(you may have to add lines if needed).
1 void delMultiple (NodePtr Head, int delKey){ 2 NodePtr prev, cur = Head; 3 while(cur!=NULL){ 4 if(cur->data > delKey && cur->data % delKey == 0){ 5 if(cur!=Head) 6 Head = Head->next; 7 else 8 prev->next = cur; 9 NodePtr tmp = cur; 10 11 delete tmp; 12 } 13 else{ 14 15 cur = cur->next; 16 } 17 } // end of while 18 }

Answer(10 marks, 2 each): (-2 for each additional mistake) (1) (2) (3) (4) (5) line line line line line 1: should be pass by refernece 5: change to if(cur==Head) 8: change to prev->next = cur-> next 10: add cur = cur->next 14: add prev = cur

Question 5: Algorithms on Linked List (14 marks)


a) Find the errors and correct them. (7 marks) Given the following definitions and function prototypes:
struct Node{ int data; Node *next; }; typedef Node* NodePtr; //return the pointer of the node having data=item //return NULL if item does not exist in the list NodePtr searchNode(NodePtr Head, int item){ } //insert item into linked list according to ascending order void insertNode(NodePtr& Head, int item){ }

The following code segment is supposed to return the union of two simple linked lists. Assume the two functions, searchNode() and insertNode(), work properly, identify errors in the code and fix them.
1. void UnionLists(NodePtr Head1, NodePtr Head2){ 2. NodePtr Union, Cur; 3. Union = Head1; 4. Cur = Head2; 5. while(Cur != NULL){ 6. if(searchNode(Union, Cur->data)) 7. insertNode(Union, Cur->data); 8. Cur = Cur->next; 9. } 10. return Head2; 11. }

Answer(7 marks): a) Line 1: void should be NodePtr // 1 mark b) Line 6 should be: if(searchNode(Union, Cur->data)==NULL) // 2 marks c) Line 10: Head2 should be Union (-1 or more for adding other errors) // 2 marks

b) Given the following definition of an element in a linked-list:


struct Mylist{ int data; Mylist* next; }; typedef Mylist* MylistPtr;

Write a function, findTotal(), which takes a simple linked list and returns the sum of all linked-list data. (7 marks)

Answer(7 marks): int findTotal(MylistPtr head){ int total = 0; while(head!=NULL){ total += head->data; head = head->next; } return total; } (-1 or more for adding other errors) // // // // // 1 1 1 2 1 mark mark mark marks mark

//1 mark

10

Question 6: Doubly Linked List (18 marks)


We will use the following definitions throughout this question:
struct Node { int data; Node* next; Node* prev; }; typedef Node* NodePtr;

a) Write a print function for a doubly linked list with dummy head node such that all the elements are printed out in the REVERSE order. For example, your function should print out 30 20 10 for the following doubly linked list: (4 marks)

10

20

30

Head

Void print(NodePtr Head){ // please add your code here

Answer(4 marks): void print(NodePtr Head){ NodePtr Cur = Head->prev; // 1 mark

11

while (Cur!=Head){ // 1 mark cout << Cur->data << ; // 1 mark Cur = Cur->prev; // 1 mark } cout << endl; } b) Write a function to add a node at the end of a doubly linked list with dummy head node.(7 marks)
void insertEnd(NodePtr& Head, int item){ // please add your code here

Answer(7 marks, 1 for each line): void insertEnd(NodePtr& Head, int item){ NodePtr New,Cur; New = new Node; New->data = item;

12

New->next = Head; New->prev = Head->prev; Head->prev = New; New->prev-next = New; }

c) Somebody has built a partially doubly linked list(Figure 1) by using only the first two member variables of the node, data and the next pointer, while leaving the prev pointer unused. In Figure 1, Head is a pointer pointing to the dummy head.

10

20

30

Head Figure 1

Now write a function to convert the above partially doubly linked list into a doubly linked list. It should take the Head pointer of a partially doubly linked list(as shown in Figure 1), and return the head of the doubly linked list(as shown in Figure 2). Use what we have already got, DO NOT allocate any new nodes. (7 marks)

10

20

30

Head Figure 2

NodePtr convertToDoubly(NodePtr Head){ // please add your code here. // DO NOT build the doubly linked list from scratch.

Answer(7 marks): NodePtr convertToDoubly(NodePtr Head){ NodePtr ptr1 = Head; NodePtr ptr2 = Head->next; do{ // 1 mark // 1 mark]

13

ptr2->prev = ptr1; ptr1 = ptr1->next; ptr2 = ptr2->next; }while(ptr1!=Head); return Head;


}

// 1 mark // 1 mark // 1 mark // 1 mark // 1 mark

Question 7: Classes(10 marks)


Consider the following class and answer questions.
#include <iostream> #include <string> using namespace std; class Currency { private: string code; double amount; public: Currency(); Currency(double amt, string c = "HKD"); string getCode() const { return code; }; double getAmount() const { return amount; }; void add (double amt) { amount += amt; }; Currency exchange(string newCode, double rate); void print(); }; Currency::Currency() { code = "HKD"; amount = 0; } Currency::Currency(double _amount, string _code) { code = _code; amount = _amount; } void Currency::print()const { cout << code << " " << amount; }

a) What is wrong with the following code? (2 marks)


int main () { Currency x, y;

14

x.add (3.9); if (x.code == y.code) cout << "Same code!" << endl; else cout << "Different code." << endl; return 0; }

Answer: (2 marks) Cannot access the private data directly

b) What is the output of the following program? (3 marks)


int main () { Currency a, b(16.8); Currency c(100.5, "EUR"); a.add (2.3); b.print(); cout << endl; c.print(); cout << endl; a.print(); return 0; }

Answer: (3 marks, 1 for each) HKD 16.8 EUR 100.5 HKD 2.3 c) The member function exchange is used to buy a foreign currency under a specified exchange rate using the amount of money stored in an object. For example:
Currency dollar = Currency(10, "USD"); Currency cad = dollar.exchange("CAD", 1.1969);

Then cad.amount == 11.969 and cad.code == "CAD". Write the implementation of the member function "exchange". The data in the original object should not be modified by this function. (5 marks)

Answer: (5 marks) Currency Currency::exchange(string newCode, double rate) { // 1 mark // should not modify any data members; otherwise, zero mark double new_amount = amount * rate; // 1 mark
15

Currency r(newCode, new_amount); return r; }

// 2 marks, 1 for right constructor, 1 // for passing correct values // 1 mark

Question 8: Dynamic Classes/ADT (24 marks)


A class OrderList will implement an ordered integer list (in increasing order) using linked list (singly linked without dummy head). The class is defined as follows:
struct Node { int data; Node* next; }; typedef Node* Nodeptr; class OrderList { public: // default constructor OrderList(); // copy constructor OrderList(const OrderList& list); // destructor ~OrderList(); // return true if the list is empty bool empty() const; // add an integer into the ordered list void addElement(int item); // delete the integer from the ordered list void delElement(int item); // return the length of the list int length() const; // print all the element in the list void print() const; // merge two sorted lists into one sorted list OrderList merge(const OrderList& list) const; private: Nodeptr head; };

16

a) Implement the member function empty(). (1 mark)


bool OrderList::empty() const {

Answer: (1 mark) return (head = = NULL); Its also fine with return (length()==0);

b) Implement the destructor of this class. (3 marks)


OrderList::~OrderList (){

Answer: ( 3 marks) Nodeptr cur;

17

while(head!=NULL){ // 1 mark cur = head; head = head->next; delete cur; // 1 mark }

// 0.5 pt // 0.5 pt

c) Complete the implementation of the member function addElement(int item) that adds the given element to the list in increasing order (6 marks):

void OrderList::addElement(int item){ Nodeptr newp, cur, pre; pre = NULL; cur = head; // first, find the position cur and pre while( (cur != NULL) && (item>cur->data)){ pre = cur; cur = cur->next; } if ((cur == NULL) || (item != (cur->data))) { // second, if the element is not already in the list // create and insert the element right before cur

} // end of if

18

} // end of function

Answer: (6 marks) newp = new Node; // 1 mark for creation newp->data = item; // if dont treat special case, 3 marks
If (pre == NULL){ // 1 mark newp->next = head; // 1 mark head = newp; // 1 mark } else { pre->next = newp; // 1 mark new->next = cur; // 1 mark }

d) Implement the copy constructor, which takes a list and makes a copy of it. You can use addElement() method as defined in the previous question. (4 marks)
OrderList::OrderList(const OrderList& list){

Answers: (4 marks) head = NULL; // 0.5 mark Nodeptr cur = list.head; // 0.5 mark while(cur != NULL) { // 1 mark addElement(cur->data); // 1 mark cur = cur->next; // 1 mark }

19

e) The method merge is supposed to merge the two ordered lists into one ordered list. For example, there is an ordered integer list, list1, and another list, list2, list1.merge(list2) will return the merged list. Both list1 and list2 will not be changed after merging. Write the implementation of this member function. You can use the member function void addElement(int data) that has been already defined. (8 marks)
OrderList OrderList::merge(const OrderList& list2) const {

20

Answer: (8 marks) Solution 1: OrderList OrderList::merge(const OrderList& list2) const { Nodeptr Cur1, Cur2; Cur1 = head; Cur2 = list2.head; // proper declaration/initialization, 1 mark OrderList result; // creation of result 1 mark // totally 2 marks for the first part of result while((cur2 != NULL) { // 1 mark result.addElement(Cur2->data); // 0.5 mark Cur2 = Cur2->next; // 0.5 mark } // or OrderList result(list2); // totally 3 marks for the second part while((cur1 != NULL) { // 1 mark result.addElement(Cur1->data); // 1 mark Cur1 = Cur1->next; // 1 mark } return result; } Solution 2: this solution totalizing 11 marks is more difficult than the first one, but more efficient. We will try to give as many as marks we can up to 8. use addEnd instead of addElement is correct (even better), but not addHead OrderList OrderList::merge(const OrderList& list2) const { Nodeptr Cur1, Cur2; Cur1 = head; Cur2 = list2.head; // 1 mark // the algorithm consists of 2 major parts. // 1 mark

OrderList result; // // // //

// 1 mark

first, we examine two lists element by element. Each time, we compare the beginning elements of the two lists, take the smaller one, add it to the resulting list, and move forward for the following elements.

21

while ((Cur1 != NULL) && (Cur2 != NULL)){ // condition: 1 marks if (Cur1->data > Cur2->data){ // 1 mark result.addElement(Cur2->data); // 0.5 mark Cur2 = Cur2->next; // 0.5 mark } else { result.addElement(Cur1->data); // 0.5 mark Cur1 = Cur1->next; // 0.5 mark } }

// second, // there may still be elements left over in one of the lists, // we add these remaining elements in the final result. while (Cur1 != NULL) { // 1 mark result.addElement(Cur1->data); // 0.5 mark Cur1 = Cur1->next; // 0.5 mark } while (Cur2 != NULL) { // 1 mark result.addElement(Cur2->data); // 0.5 mark Cur2 = Cur2->next; // 0.5 mark } return result; } // 1 mark

f) Explain the meaning of two const in the prototype of the function merge. (2 marks)
OrderList OrderList::merge(const OrderList& list2)

const

(1) (1 mark) the first const before OrderList& :

22

(2) (1 mark) the second const at the end of the line after the closing parenthesis:

Answer: (2 marks, 1 for each) (1) The const before OrderIntList& is to ensure object list1 (or calling object) won be altered. (2) The const at last of the function merge is to ensure the object itself does not change.

23

You might also like