0% found this document useful (0 votes)
55 views15 pages

Name: Section: TA: Expected Score (Just Guess) :: CSE 143, Summer 1995 Final Exam (100 Points) Date: 8/18/95

Here is the binary search tree that results from inserting the values in the given order: 5 / \ 3 8 / \ \ 2 4 9 / 1 \ 6 \ 7 (b) [6] What is the worst-case running time of a binary search tree insertion? Justify your answer. The worst-case running time of a binary search tree insertion is O(h) where h is the height of the tree. This occurs when the tree becomes a linked list, i.e. when values are inserted in ascending or descending order. In this case, the height h is O(n) where n is the number of nodes,

Uploaded by

Ishan Jawa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PS, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
55 views15 pages

Name: Section: TA: Expected Score (Just Guess) :: CSE 143, Summer 1995 Final Exam (100 Points) Date: 8/18/95

Here is the binary search tree that results from inserting the values in the given order: 5 / \ 3 8 / \ \ 2 4 9 / 1 \ 6 \ 7 (b) [6] What is the worst-case running time of a binary search tree insertion? Justify your answer. The worst-case running time of a binary search tree insertion is O(h) where h is the height of the tree. This occurs when the tree becomes a linked list, i.e. when values are inserted in ascending or descending order. In this case, the height h is O(n) where n is the number of nodes,

Uploaded by

Ishan Jawa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PS, PDF, TXT or read online on Scribd
You are on page 1/ 15

CSE 143, Summer 1995

Final Exam (100 points)


Date: 8/18/95

This exam contains 15 pages!

Name:
Section:
TA:
Expected Score (just guess):

1 (8)
2 (10)
3 (10)
4 (4)
5 (8)
6 (8)
7 (10)
8 (6)
9 (10)
10 (10)
11 (4)
12 (4)
13 (8)
TOTAL (100)

1
In the problems in this test, assume the following declarations:

class Node {
public:
Node(int in_data, Node* in_next);
int data;
Node* next;
};

class List {
public:
List();
private:
Node* head;
};

List::List()
{
head = NULL;
}

Node::Node(int in_data, Node* in_next)


{
data = in_data;
next = in_next;
}

2
1. [8 points] Pointers and Dynamic Memory
In each of the following pictures, assume
Node* x, y;
and show the effect of executing the following statement (by changing the appropriate data/point-
ers). Also, circle any garbage and cross out any Node returned to free memory and draw in new
nodes as appropriate.
(a) y = new Node(10, y);

x 3 1 5 2 4

10
y

(b) *x->next = *x;

x 3 13 5 2 4

(c) y->next->next = new Node(y->data, y->next->next);

x 3 1 5 2 4

(d) delete x->next;

x 3 1 5 2 4

3
2. [10 points] Add a get_size() member function to the List class. Also add a get_size() mem-
ber function to the Node class. The former should call the latter to return the size of the
list. The latter should be a recursive function. Show both the specification and the imple-
mentation of both functions.

SOLUTION:

class Node {
public:
int get_size() const;
};

class List {
public:
int get_size() const;
};

int Node::get_size() const


{
if (next == NULL) {
return 1;
} else {
return 1 + next->get_size();
}
}

int List::get_size() const


{
if (head == NULL) {
return 0;
} else {
return head->get_size();
}
}

4
3. [10 points] Implement the function to reverse the elements of a List object.
The prototype of this member function of the List class looks like this:
void List::reverse();
You may define other functions to help you write this one.

SOLUTION 1 (iterative):
void List::reverse()
{
if ((head == NULL) || (head->next == NULL)) {
return;
}

Node* p = head; // p points to the first node


Node* q = head->next; // q points to the current node we look at
p->next = NULL; // set the first node’s next pointer to NULL
while (q != NULL) {
Node* r = q; // r “r”emembers the first node
q = q->next; // q moves to the next node
r->next = p; // link to the previous node
p = r; // previous node is now r
}
head = p; // when you run out of nodes, p is the new head
}

SOLUTION 2 (recursive):
void Node::reverse(Node* p, Node*& tail)
{
if (next == NULL) { // base case, when you reach the last node
next = p; // p points to the previous node
tail = this; // tail is the pointer to the last node
return;
} else { // recursive case
next->reverse(this, tail);
next = p; // a chain reaction to reverse all pointers
}
}

void List::reverse()
{
if (head) {
head->reverse(NULL, head);
}
}

5
4. [4 points] Imagine that you’re working on a large project with a number of nice but not
too smart other people. You know that your colleagues assume that any code that com-
piles is perfectly okay.

They have written a class whose definition is

class myString {

public:

myString();

~myString();

const char* GetData() const {return theString;}

Boolean operator= (const char*);

Boolean operator= (const myString&);

friend ostream& operator<< (ostream&, const myString&);

private:

int length;

char* theString;

};

There are at least 4 unsafe features in the class definition and for each unsafe feature, suggest a
better way to write C++ code. You may simply modify the code above to show what changes you
suggest. You may not add or remove an entire member funciton or data member.

SOLUTION is in red. It will be easier to pick up the solution using a color terminal and look at
the postscript version of the solution.

6
5. [8 points] C++ classes
(a) [4] In C++, 4 member functions have default behavior, i.e., they do not need to be explicitly
declared by you. What are those 4 member functions? Be as specific as possible.

• default constructor
• copy constructor
• destructor
• assignment operator

(b) [4] Under what circumstances would you like to define each of the four member functions
mentioned above?

• default constructor - e.g. to initialize an object with proper values when the object is defined.
• copy constructor - e.g. when shallow copying is not acceptable.
• destructor - e.g. when it is necessary to destroy dynamically allocated objects.
• assignment operator - e.g. when shallow copying is not acceptable.

7
6. [8 points] Consider linked list implementations.
(a) What is the major advantage of using the head node implementation?

• Don’t have to deal with the special case that the head pointer may need to be changed.
• This makes insertion and deletion of nodes in a list easier to write.

(b) What is the major advantage of using a doubly linked list?

• Easy to traverse in either forward or backward direction.

(c) What is the major advantage of using a linked list over an array implementation of a list?

• easy to expand or contract depending on the number of elements.

(d) What is the advantage of using dynamic arrays (growing and shrinking arrays) over pointer
implementation of a linked list?

• direct access (e.g. using subscript operators) to elements.

8
7. [10 points] Time Complexity
(a) Why do we use big-oh notation to describe the time complexity of algorithms rather than
directly reporting running times?
• Running times are machine dependent.
• An estimate of the worst case scenario.
• Simple to use because we drop constants and only keep the dominant term.
Give the worst-case run-time of the following functions
(b) O(n2)
int runMe(int n)
{
int result = 0;
for (int i = 0; i < (n/100); i+=2) {
for (int j = 0; j < 10; j++) {
for (int k = -10; k < 5*n; k++) {
result += k;
}
}
}
}
(c) O(n)
// assume pow(2,n) computes 2n in constant time.
int runMeToo(int n)
{
int i, result = 0;
for (i = 1; i < pow(2, n); i*=2)
result += i;
}
(d) O(log a)
int fun(int a)
{
if (a <= 1) {
return 1;
} else {
return 1 + fun(a/5);
}
}
(e) O(2a)
int fun(int a)
{
if (a <= 5) {
return 1;
} else {
return fun(a - 1) + fun(a - 3);
}
}

9
8. [6 points] Identify the major problem in each of the following functions:
(a)

void FunctionA( MyType *x ) {


MyType *y = new MyType;
*y = *x;
}

• inaccessible object (*y) because y’s object is no longer accessible when this function returns.

(b)

MyType* FunctionB( MyType *x ) {


MyType y;
y = *x;
return &y;
}

• returning the address of an object (y) which will be deallocated when this function returns.

(c)

void FunctionC( MyType *x ) {


MyType *y;
y = new MyType;
y = x;
delete y;
}

• major problem: x is left as a dangling pointer.


• minor problem: an inaccessible object (*y) when this function returns.

10
9. [10 points] To create a binary search tree, we can repeatedly apply the binary search tree inser-
tion algorithm until all values have been inserted.
(a) [4] For the following integer sequences, show the binary search tree that results from insert-
ing in the specified order: 3, 2, 1, 9, 7, 8, 5, 4, 6.

2 9

1 7

5 8

4 6

(b) [2] Give the order in which nodes of this tree are visited by preorder traversal.

• 321975468

(c) [2] Give the order in which nodes of this tree are visited by inorder traversal.

• 123456789

(d) [2] Give the order in which nodes of this tree are visited by postorder traversal.

• 124658793

11
10. [10 points] A ternary tree is a tree with at most three children per node and with each
child designated as left, right, or middle child.
(a) [4] Write the type declarations necessary to implement a ternary tree as a linked structure
with each tree node represented as a Ternary_Node class. Each node needs to contain an int
value. (Solution in red)
class Ternary_Node {
public:
void preorder_print(ostream& ost) const;
private:
int data;
Ternary_Node* left;
Ternary_Node* middle;
Ternary_Node* right;
};

(b) [6] Write a preorder traversal algorithm for this ternary tree. The preorder traversal function
should be a member function of the Ternary_Node class. It should print the int values of the
nodes while traversing the tree.

void Ternary_Node::preorder_print(ostream& ost) const


{
ost << data << “ “;
if (left) {
left->preorder_print(ost);
}
if (middle) {
middle->preorder_print(ost);
}
if (right) {
right->preorder_print(ost);
}
}

12
11. [4 points] Consider the following code:

class Birthday {
public:
Birthday(int day, int month, int year);
private:
int day, month, year;
};

class Grand_Parent {
public:
Grand_Parent(const Birthday& birthday);
private:
Birthday my_birthday;
};

class Parent: public Grand_Parent {


Parent();
private:
int data;
};

Parent::Parent()
{
data = 0;
}

(a) [2] What are two compilation problems in the code above?
• A problem in Grand_Parent, my_birthday, because Birthday does not have a default construc-
tor.
• Another problem in Parent’s default constructor, because Grand_Parent does not have a default
constructor.
(b) [2] How can the compilation problems be removed? (You may just change the code above.
You don’t have to rewrite anything that is not necessary.)
• Provide a default constructor in each case.
• Rewrite the Parent’s constructor to use an initailizer.
• Rewrite the Grand_Parent’s data member to use a pointer and allocate a Birthday object in the
constructor.
• Many many other solutions.

13
12. [4 points] Consider the following code:

class Grand_Parent {
// ...
};

class Parent : public Grand_Parent {


// ...
};

class Child : public Parent {


// ...
};

For each of the following, say if there is a compilation error. If not, say if there is a potential run
time error.
(a)

Grand_Parent* g = new Child;

• okay.

(b)

Child* c = new Parent;

• compilation error.

(c)

Grand_Parent* g = (Grand_Parent*) new Child;

• okay.

(d)

Child* c = (Child*) new Parent;

• possible run-time error when some members of c are accessed.

14
13. [8 points] Consider the code below:
class Person {
public:
Person(long in_ssn): ssn(in_ssn) {}
virtual void write(ostream& ost) { ost << “Person: “ << ssn << endl; }
protected:
long get_ssn() const { return ssn; }
private:
long ssn;
};

class Student : public Person {


public:
Student(long in_id, long in_ssn): Person(in_ssn), id(in_id) {}
private:
long id;
};

class Staff : public Person {


public:
Staff(long in_salary, long in_ssn): Person(in_ssn), salary(in_salary) {}
void raise_salary(long in_amount) { salary += in_amount; }
void write(ostream& ost) { ost << “Staff: “ << salary << endl; }
protected:
long salary;
};

class Faculty : public Staff {


public:
Faculty(long in_salary, long in_ssn): Staff(in_salary, in_ssn) {}
void raise_salary(long in_amount) { salary += 2 * in_amount; }
void write(ostream& ost) { ost << “Faculty: “ << salary << endl; }
private:
// ... too private to tell
};

What should be the output from the following code? (Solution in red)

Staff* tompa = new Faculty(1000, 123456789);


tompa->raise_salary(100);
tompa->write(cout);
Faculty: 1100
Person* omid = new Faculty(2000, 987654321);
omid->write(cout);
Faculty: 2000
Person* kingsum = new Student(9500000, 123123123);
kingsum->write(cout);
Person: 123123123
Faculty juan(3000, 456111111);
juan.raise_salary(2000);
juan.write(cout);
Faculty: 7000

15

You might also like