Final Exam Review Solutions - Lab: Computer Programming and Problem Solving | CS 111, Study notes of Computer Science

Material Type: Notes; Class: LAB:Comp Program & Prob Solv; Subject: Computer Science; University: Wellesley College; Term: Spring 2002;

Typology: Study notes

Pre 2010

Uploaded on 08/19/2009

koofers-user-znj
koofers-user-znj 🇺🇸

10 documents

1 / 21

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
1
Wellesley College CS111 Computer Programming and Problem Solving Spring 2002
FINAL EXAM REVIEW SOLUTIONS
This final draft contains solutions to all problems.
____________________________________________________________________________
Problem 1: Sales Statistics (Data Abstraction, Arrays, Lists, Objects, Object Diagrams)
Part a.
purchases
size
h
History
3
0 1 2 3 4
Purchas[ ]
amount
cash false
82 amount
cash true
53 amount
cash false
178
Purchase Purchase Purchase
Part b. Finishing the instance methods of the History class:
public class History {
// Instance Variables:
private Purchase [ ] purchases;
private int size;
// Constructor Method:
public History (int maxEntries) {
purchases = new Purchase[maxEntries];
size = 0;
}
// Instance Methods:
public void add (int amount, boolean cash) {
if (size < purchases.length) {
purchases[size] = new Purchase(amount, cash);
size = size + 1;
}
}
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15

Partial preview of the text

Download Final Exam Review Solutions - Lab: Computer Programming and Problem Solving | CS 111 and more Study notes Computer Science in PDF only on Docsity!

Wellesley College ◊ CS111 Computer Programming and Problem Solving ◊ Spring 2002

FINAL EXAM REVIEW SOLUTIONS

This final draft contains solutions to all problems.

____________________________________________________________________________

Problem 1: Sales Statistics (Data Abstraction, Arrays, Lists, Objects, Object Diagrams)

Part a.

purchases

size

h

History

Purchas[ ]

amount

cash false

82 amount

cash true

53 amount

cash false

Purchase Purchase Purchase

Part b. Finishing the instance methods of the History class:

public class History {

// Instance Variables: private Purchase [ ] purchases; private int size;

// Constructor Method: public History (int maxEntries) { purchases = new Purchase[maxEntries]; size = 0; }

// Instance Methods: public void add (int amount, boolean cash) { if (size < purchases.length) { purchases[size] = new Purchase(amount, cash); size = size + 1; } }

public int size(){ return size; }

public int min(boolean cash){ int minVal = Integer.MAX_VALUE; for (int i = 0; i < size; i ++){ if (purchases[i].getCash() == cash){ if(purchases[i].getAmount() < minVal){ minVal = purchases[i].getAmount(); } } } return minVal; }

public int max(boolean cash){ int maxVal = Integer.MIN_VALUE; for (int i = 0; i < size; i ++){ if (purchases[i].getCash() == cash){ if(purchases[i].getAmount() > maxVal){ maxVal = purchases[i].getAmount(); } } } return maxVal; }

public int average(boolean cash){ int sum = 0; int count = 0; for (int i = 0; i < size; i++){ if(purchases[i].getCash() == cash){ sum = sum + purchases[i].getAmount(); count = count + 1; } } if (count == 0){ return 0;

} else { return sum/count; } }

public int number (boolean cash){ int count = 0; for (int i = 0; i < size; i ++) { if(purchases[i].getCash() == cash){ count = count + 1; } } return count; }

public int percentage (boolean cash){ if (size > 0){ return (number(cash) * 100)/size; }else{ return 0; } } }

2) Implement Purchase class with an integer list:

public class Purchase {

// Instance Variables private IntList sale;

// Constructor Method public Purchase (int i, boolean b) { sale = prepend(i, prepend(intToBool(b), empty())); }

// Instance Methods public int getAmount () { return head(sale); }

public void setAmount (int newAmount) { sale = prepend(newAmount, tail(sale)); }

public boolean getCash () { return (head(tail(sale)) == 1); }

public void setCash (boolean newCash) { sale = prepend(head(sale), prepend(intToBool(newCash), empty())); }

// Useful helper method private bool boolToInt (boolean b) { if(b){ return 1; } else { return 0; } } }

3) Implement Purchase class as a single positive or negative integer:

public class Purchase {

// Instance Variables private int sale;

// Constructor Method public Purchase (int i, boolean b) { sale = (sign(b)) * i }

// Instance Methods public int getAmount () { return Math.abs(sale); }

public void setAmount (int newAmount) { sale = sign(sale) * Math.abs(newAmount); }

public boolean getCash () { return (sale > 0); }

public void setCash (boolean newCash) { sale = sign(newCash) * Math.Abs(sale); }

// Useful helper method public int sign (boolean b) { if (b) { return 1; } else { return –1; } } }

Part f. Implement history with 3 instance variables: maxEntries, and two IntLists:

i.

ii. Implementation

public class History {

// Instance Variables: private int maxEntries; private IntList cashes; private IntList credits;

// Constructor Method: public History (int maxEntries) { this.maxEntries = maxEntries; cashes = empty(); credits = empty(); }

// Instance Methods: public void add (int amount, boolean cash) { if (length(cashes) + length(credits) < maxEntries) { if (cash){ cashes = prepend(amount, cashes); } else { credits = prepend(amount, credits); } } }

public int min(boolean cash){ if (cash){ return minOfList(cashes); } else { return minOfList(credits); } }

public int minOfList(IntList L){ if(isempty(L)){ return Integer.MAX_VALUE; } else { int minVal = minOfList(tail(L)); if(head(L) < minVal){ return head(L); } else { return minVal; } } }

public int size(){return length(cashes) + length(credits);}

public int max(boolean cash){ //similar to min--left as exercise.}

public int average(boolean cash){ if(cash){ if(isempty(cashes){ return 0; } else { return sum(cashes)/length(cashes); } }else { if(isempty(credits){ return 0; } else { return sum(credits)/length(cashes); } } }

private int sum (IntList L) { if(isempty(L)){ return 0; } else { return head(L) + sum(tail(L)); } }

private int length (IntList L) { if(isempty(L)){ return 0; } else { return 1 + length(tail(L)); } }

public int number (boolean cash){ if(cash){ return length(cashes); } else { return length(credits); } }

public int percentage (boolean cash){ if (size() != 0){ if (cashes){ return length(cashes) * 100/size(); }else{ return length(credits) * 100/size(); } } else { return 0; } } }

Part g. Left as exercise for the student.

An alternative solution can be written using the fact that the slots of subresult can be modified directly rather

than returning a freshly allocated array. This implementation is shown below:

public static IntList [] partitionNonTail ( int pivot, IntList L) { if (isEmpty(L)) { // base case for recursion return twoLists (empty(), empty()); } else { // general case // solve the smaller problem via wishful thinking IntList [] subresult = partitionNonTail(pivot, IL.tail(L));

// add the first element of the list to the appropriate component if (IL.head(L) <= pivot) { // update lesse s subresult[0] = IL.prepend(IL.head(L), subresult[0]); } else { // update greaters subresult[1] = IL.prepend(IL.head(L), subresult[1]); }

return subresult; } // end general case }

Part d. Quicksort is one method to sort a list of numbers into numerical order. Quicksort works recursively

and its algorithm was described in the problem set description. To implement quicksort, we need to figure out

what is its base case and what is its general case and what to do in each situation.

• base case : a sorted empty list is the empty list (there are no elements to sort!)

• general case :

♦ partition the elements of the list (except for the first element) into two piles: elements less than the

first element, and elements greater than or equal to the first element

♦ sort each pile (the lesses and the greaters) using quicksort

♦ obtain our final answer by placing the three components in order: the sorted lesses, the first element,

the sorted greaters

Code that implements the above quicksort algorithm is shown below:

public static IntList quickSort(IntList L) { if (IL.isEmpty(L)) { // base case for recursion return IL.empty(); } else { // general case IntList [] partitions = partition(IL.head(L), IL.tail(L)); IntList lesses = partitions[0]; IntList greaters = partitions[1]; return IL.append(quickSort(lesses), IL.prepend(IL.head(L), quickSort(greaters))); } // end general case }

________________________________________________________________________________

Problem 3: Squares (Recursion, Iteration, TurtleWorld, BuggleWorld, PictureWorld, Java Graphics)

Part a. Turtle World

public void squares( int n, int len) { if (n > 0) { drawSquare(len); fd(len); squares(n - 1, len/2); bd(len); } }

public void drawSquare( int length) { for (int i = 0; i < 4; i++) { fd(length); lt(90); } }

Part b. Buggle World

public void squares( int n, int len) { if (n > 0) { bagelRect(len,len); forward(len); squares(n - 1, len/2); backward(len); } }

// Draw a rectangle of bagels with the given width and height. // The state of the buggle is invariant under this method. public void bagelRect( int width, int height) { if (height > 0) { bagelLine(width); left(); forward(1); right(); bagelRect(width, height-1); left(); backward(1); right(); }

// Drop a line of width bagels, leaving the state of the buggle invariant public void bagelLine( int width) { if (width > 0) { dropBagel(); forward(); bagelLine(width-1); backward(); }

________________________________________________________________________________

Problem 4: Greatest Common Divisor (Iteration)

Part a. Here is the iteration table for the iterative calculation of GCDTail(95,60).

A B

Part b.

public static int GCDWhile ( int A, int B) { while (B != 0) { // Need a temporary variable to perform updates! int oldA = A; A = B; B = oldA % B; } return A; }

Part c. It is always possible to express a while loop as a for loop, but the result may not be particularly

natural. Indeed, in this case it would not be natural to re-express Wyla's GCDTail program as a for loop. For

loops best “fit” cases where there is a state variable controlling the number of times through the loop that is

independent of other state variables. In the case of GCD, the state variable B controls the number of times

through the loop, suggesting the following skeleton:

public static int GCDFor ( int A, int B) { for (; B != 0; B = A % B) { // No initialization of B necessary updates } return A; }

But what should replace updates? If we put A = B in this position, then the A in A % B (which is executed after

updates) is the value of A after the assignment, when we want the value of A before the assignment. We need a

temporary variable to circumvent this problem, as shown below:

public static int GCDFor ( int A, int B) { int oldA; for (; B != 0; B = oldA % B) { // No initialization of B necessary oldA = A; A = B; } return A; }

This method is less straightforward than the while loop, which is much clearer and therefore preferred.

________________________________________________________________________________

Problem 5: Array Reversal (Arrays, Iteration)

Part a.

public static int [] copyReverse ( int [] a) { int len = a.length; int [] result = new int [len]; for ( int i = 0; i < len; i++) { result[i] = a[(len–1)–i]; // (len–1) is last slot } return result; }

Part b.

public static int [] reverse ( int [] a) { int len = a.length; // Swap first (len/2) slots with last (len/2) slots // If len is odd, middle slot stays unchanged for ( int i = 0; i < len/2; i++) { // Swap contents of slot i and (len-1)-i int old_a_sub_i = a[i]; a[i] = a[(len-1)-i]; a[(len-1)-i] = old_a_sub_i; } }

________________________________________________________________________________

Problem 6: Inversions (Arrays, Iteration, Lists)

Part a.

// Returns the number of inversions in a: public static int countInversions ( int [] a) { int invs = 0; // Counts number of inversions for ( int i = 0; i < a.length; i++) { for ( int j = i+1; j < a.length; j++) { if a[i] > a[j] { invs = invs + 1; } } } return invs; }

Part b. Suppose that OL. is the prefix used for operations on ObjectLists

// Returns the inversions in a as a list of points public static int countInversions ( int [] a) { ObjectList points = OL.empty(); // Collects inversions as list of points for ( int i = 0; i < a.length; i++) { for ( int j = i+1; j < a.length; j++) { if a[i] > a[j] { points = OL.prepend( new Point(i,j), points); } } } return points; }

// For loop public static boolean isMemberFor ( int n, int [] a) { int i = a.length - 1; for (int i = a.length – 1; i>=0; i--) { if a[i] == n { return true; } } return false; }

// Tail recursion public static boolean isMemberIter ( int n, int [] a) { return isMemberTail(n, a, a.length - 1); }

public static boolean isMemberTail ( int n, int [] a, int i) { if (i < 0) { return false; } else if (a[i] == n) { return true; } else { return isMemberTail (n, a, i-1); } }

Part c.

// For loop public static void partialSum ( int [] a) { int sum = 0; for (int i = 0; i < a.length; i++) { sum = sum + a[i]; a[i] = sum; } }

// While loop public static void partialSumWhile ( int [] a) { int i = 0; int sum = 0; while (i < a.length) { sum = sum + a[i]; a[i] = sum; i++; } }

// Tail recursion public static void partialSumIter ( int [] a) { return partialSumTail(a,0, 0); }

public static void partialSumTail (int [] a, int i, int sum) { if (i < a.length) { int newsum = sum + a[i]; a[i] = newsum; partialSumTail(a, i+1, newsum); } }

Part d.

// Tail recursion public static void squiggle (Graphics g, int x1, int y1, int x2, int y2) { if ((x1 > 0) || (y1 > 0) || (x2 > 0) || (y2 > 0)) { g.drawLine(x1, y1, x2, y2); squiggle(g, x2, y2, y1/4, x1*2); } }

// While loop public static void squiggleWhile (Graphics g, int x1, int y1, int x2, int y2) { while ((x1 > 0) || (y1 > 0) || (x2 > 0) || (y2 > 0)) { g.drawLine(x1, y1, x2, y2); // Introduce temporaries for x1, y1 so don’t lose their values! old_x1 = x1; old_y1 = y1; x1 = x2; y1 = y2; x2 = old_y1/ y2 = old_x1*2; } }

// For loop public static void squiggleFor (Graphics g, int x1, int y1, int x2, int y2) { // A particularly uncompelling example of a for loop! for (;(x1 > 0) || (y1 > 0) || (x2 > 0) || (y2 > 0);) { g.drawLine(x1, y1, x2, y2); // Introduce temporaries for x1, y1 so don’t lose their values! old_x1 = x1; old_y1 = y1; x1 = x2; y1 = y2; x2 = old_y1/ y2 = old_x1*2; } }

________________________________________________________________________________

Problem 9: Converting Betweeen Arrays and Lists (Lists, Arrays, Iteration)

public static int [] listToArray (IntList L) { int [] result = new int [IL.length(L)]; int i = 0; while (! isEmpty(L)) { result[i] = IL.head(L); L = IL.tail(L); i = i + 1; } return result; }

public static IntList arrayToList ( int [] a) { IntList L = IL.empty(); // traverse the array from back to front in order // to prepend elements in the correct order. for (int i = a.length – 1; i >= 0; i--) { L = prepend(a[i], L); } return L; }

Part b.

Tail recursive solution:

public static IntList reverseIter (IntList L) { return reverseTail(L, IL.empty()); }

public static IntList reverseTail (IntList list, IntList result) { if (IL.isEmpty(list)) { return result; } else { return reverseTail(IL.tail(list), IL.prepend(IL.head(list), result)); } }

While loop solution:

public static IntList reverseWhile (IntList L) { IntList result = IL.empty(); while (! IL.isEmpty(L)) { result = IL.prepend(IL.head(L), result); L = IL.tail(L); } return result; }

For loop solution:

public static IntList reverseWhile (IntList L) { IntList result = IL.empty(); for (;! IL.isEmpty(L); L = IL.tail(L)) // Note empty initializer result = IL.prepend(IL.head(L), result); } return result; }

______________________________________________________________________________ Pro

blem 11: Leftist Turtles (Tests Instance Variables, Class Declarations, Inheritance)

Part a.

public class LeftistTurtle extends Turtle {

private int leftCount;

public LeftistTurtle() { super(); leftCount = 0; }

public void lt ( double degrees) { super.lt(degrees); leftCount = leftCount + 1; }

public int numberOfLefts () { return leftCount; }

}

Part b.

The example can print 2 in the case where the rt() method of the Turtle class is implemented as follows:

public void rt ( double degrees) { left(-degrees); }

In this case, every call to rt() performs an implicit call on lt()!

Part c. In the case where the Turtle method rt() calls lt(), we can add a rt() method to LeftistTurtle

that subtracts 1 from leftCount for each call to rt(). This will cancel out the 1 that is added by the implicit

call to lt().

public void rt ( double degrees) { super.rt(degrees); leftCount = leftCount - 1; }

Suppose we don’t know whether the Turtle rt() method invokes lt() or not – can we still handle rt()

correctly? Yes! The following version of the LeftistTurtle rt() method is more robust than the version

above because it makes no assumptions about how the Turtle rt() method works:

public void rt ( double degrees) { int oldLeftCount = leftCount; super.rt(degrees); // may change leftCount leftCount = oldLeftCount; // reset leftCount, in case changed by super.rt() }