1. Big O Notation [15 points]

Sketch a proof that if f(n) is O(g(n) + h(n)) and g(n) is O(h(n)) then f(n) is O(h(n)). You will most likely need to do this in terms of the definition of big-O, using the constants from the preconditions to demonstrate the constants for the conclusion.

The formal definition of big-O says that r(x) is O(s(x)) if and only if there exist n0 > 0 and d > 0 such that for all n greater than n0, |r(n)| <= |d*s(n)|. If we are going to prove that f(n) is O(h(n)) then we have to find such constants.

Since f(n) is O(g(n)+h(n)) there exist n1 > 0 and a > 0 such that for all n greater than n1, |f(n)| <= |a*(g(n)+h(n))|

Since g(n) is O(h(n)) there exist n2 > 0 and b > 0 such that for all n greater than n2, |g(n)| <= |b*(h(n))|.

We'll let n0 = max(n1,n2) and develop d on the fly.

• |f(n)| <= |a*(g(n)+h(n))| because f(n) is O(g(n)+h(n))
• <= |a*g(n) + a*h(n)| by the distributive rule
• <= |a*g(n)| + |a*h(n)| by the rule that |x+y| <= |x| + |y|
• <= a*|g(n)| + a*|h(n)| by the rule that |x*y| = x*|y| if x > 0
• <= a*|b*h(n)| + a*|h(n)| because g(n) is O(h(n))
• <= a*b*|h(n)| + a*|h(n)| by the rule that |x*y| = x*|y| if x > 0
• <= (a*b+a)*|h(n)| by the distributive rule
• <= |(a*b+a)*h(n)| by the rule that x*|y| = |x*y| if x > 0 (in this case, x is (a*b+a) which is greater than 0)

Hence, f(n) is O(h(n)), with n0 = max(n1,n2) and d=(a*b+a).

Notes

I accepted somewhat less formal proofs, as long as most of the key ideas were there.

Some of you failed to write a real proof for this problem. That is, you failed to demonstrate n0 and d that meet the criteria for f(n) being O(h(n)).

Some of you who tried to write proofs assumed that the n0 and d were always the same. This is clearly not the case.

Some of you wrote "proofs by example". While such 'proofs" are useful for establishing the potential correctness of the theorem, they are not valid as proofs.

2. Preconditions and Postconditions [15 points]

The following method multiplies two arrays of integers (representing standard mathematical vectors).

```public int multiply(int[] A, int[] B)
{
int result = 0;
for (int i = 0; i < A.length; ++i) {
result = result + A[i]*B[i];
}
return result;
} // multiply
```

What preconditions and postconditions should we state for this method?

It is meaningless to multiply two empty vectors, so we need a precondition that neither vector is empty.

It is meaningless to multiply two vectors of different sizes, so we need a precondition that the two vectors are the same size.

When we're done, we know that the result is the inner product of the two vectors. We can state a postcondition that this method returns the inner product of A and B.

If we're worried about overflow, we might also require that the inner product of A and B is less than the largest integer.

Java sets a default value for each element in an array. If we were being particularly careful, we might require that each element in each array has been assigned a value.

Notes

Most of you did well on this one. I didn't expect the last two, but was pleased when I saw them.

3. Retrieving Values from Matrices [35 points]

Here is one version of the `positionOf` method that was an optional part of assignment 3. Note the `rows` is a vector of vectors, with each subvector representing one row of the matrix. Note also that we're using zero-based indexing.

```public MatrixIndex positionOf(Object obj)
{
int col;
for (int row = 0; row < rows; ++rows) {
col = ((Vector) rows.elementAt(i)).indexOf(obj);
if (col != -1) {
return new MatrixIndex(row, col);
}
} // for
} // positionOf
```

You may want to look at the documentation for `java.util.Vector` to better understand `indexOf`. Note that while a running time isn't given, you should be able to predict one given the definition of the method.

3.1. What is the running time of this algorithm (in big-O notation)?

Problem / Apology

For some reason, the code in the printed exams didn't include the `indexOf(obj)`, which made this code almost completely ununderstandable. I decided to give you all full credit for this problem. I apologize for any stress this may have caused.

Solution

In the worst case, we do all the repetitions of the for loop. There are O(n) such repetitions (once we fix the code). Getting an element of a vector requires a single step. Getting the index of an element in a vector may require O(n) steps. Hence, this is an O(n*n) algorithm.

3.2. There are a number of problems with this code. Identify as many as you can.

Solution

• We should be incrementing `row` and not `rows`.
• `elementAt` can throw an exception. We haven't caught or passed that exception.
• Casting the result of `elementAt` to a `Vector` can throw an exception. We haven't caught or passed that exception.
• We use `row` as the counter variable in our loop, but use `i` as the parameter to `elementAt`.

4. Comparable Vectors [35 points]

Sketch a class, `ComparableVector` that extends `java.util.Vector` and includes a `lessThan(Comparable other)` method that determines whether the current vector (`this`) is less than `other`. Your class should implement `rebelsky.util.Comparable`.

Note that you may need to check whether each element in each vector is comparable. You should also concern yourself with exceptions and exception handling (catching some exceptions when appropriate, throwing others when appropriate).

Another Error

This problem originally read "Your class should extend `rebelsky.util.Comparable`." Obviously, you cannot extend two classes. The correct reading is "Your class should implement `rebelsky.util.Comparable`." Obviously, you cannot extend two classes.

Solution

```import java.util.Vector;
import rebelsky.util.Comparable;
import rebelsky.util.IncomprableException;

/**
* Vectors that we can compare to each other.  Very similar to
* java.util.Vector except that these vectors also provide a
* lessThan method.  Vector A is less than a vector B if
* (1) the size of A is less than or equal to the size of vector B;
* (2) each element of A is less than or equal to the corresponding
* element of B; and (3) at least one element of A is less than the
* corresponding element of B.
*
* @author Samuel A. Rebelsky
* @version 1.0 of March 1998
*/
public class ComparableVector
extends Vector
implements Comparable
{
// +--------------+--------------------------------------------
// | Constructors |
// +--------------+

/**
* Build a new empty vector.
*/
public ComparableVector()
{
super();
} // ComparableVector()

/**
* Build a new empty vector with a specified initial capacity.
*/
public ComparableVector(int init_capacity)
{
super(init_capacity);
} // ComparableVector(int)

// +---------+-------------------------------------------------
// | Methods |
// +---------+

/**
* Determine if the current vector is less than another
* comparable object.  See the class definition for more
* information on comparisons.
*/
public boolean lessThan(Comparable other)
throws IncomparableException
{
// One element in the current vector
Comparable this_elt;
// One element in the other vector
Comparable other_elt;
// Have we found a smaller element in this vector?
boolean smaller = false;

// If the other object is not a ComparableVector, then
// the two objects cannot be compared.
if (!(other instanceof ComparableVector)) {
throw new IncomparableException();
}

// Cast the other object to a ComparableVector for simplified
// operation.  Don't bother catching the ClassCastException since
// we know that it's of the appropriate type.
ComparableVector partner = (ComparableVector) other;

// If the other vector has fewer elements, this one isn't smaller
if (partner.size() < this.size()) {
return false;
}

// Assume the first vector is not smaller until we discover otherwise.
// If the other one is ever determined to be smaller, we will
// return false immediately.  If the other one is always at least
// as big, we will continue.
for (int i = 0; i < size(); ++i) {
try {
this_elt = (Comparable) elementAt(i);
other_elt = (Comparable) partner.elementAt(i);
if (other_elt.lessThan(this_elt) {
return false;
}
else if (this_elt.lessThan(other_elt) {
smaller = true;
}
else {
// They're equal, do nothing
}
} // try
// If we couldn't cast things to Comparable, then the
// two vectors are incomparable.  If lessThan threw an
// IncomparableException, we can just ignore pass it along.
catch (ClassCastException cce) {
throw new IncomparableException();
}
} // for
// If we've found a smaller element, then the current list
// is smaller.  Otherwise it's not (actually, it's equal).
return smaller;
} // lessThan
} // ComparableVector
```

Notes

There are a number of different criteria one could choose for A being less than B. I've chosen one common one. It was certainly acceptable if you chose another.

I did not expect you to have the full comment at the beginning of the class, but I did expect some explanation as to what was happening at each step (and a summary of what you meant by less than). Many of you included the `import` statements, but I didn't require it (given the time constraints of the exam).

I generally accepted solutions that didn't have constructors. However, I did take off points if you included an incorrect constructor.

A few of you decided that you would only allow vectors to be compared if they contained integers. That is not a reasonable design decision.

Note that only methods can throw exceptions. Some of you put a throws clause in your class definitions, which is completely meaningless.

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.