Sept. 16   Intro to pa1, finish Chap. 5

Collect hw1 (or next time), hand out paper strips with turnin usernames, also lab partner names.

Can construct turnin username from rule:  Up to 5 letters from your last name, followed by more letters of your first name until they run out or make 7 chars in all.

Initial password is "passwd", change it as soon as possible to protect your turned in files.

Note new Resources at end of class web page: generics overview and FAQ.

Sent test message out yesterday.

Qual solution: $cs210/pa1, start on pa1.

Intro to pa1

First get your qual solution or mine actually working in your IDE.

Then mods to do:

  1. Add an exception for a too-big box, assumed to be a fairly rare event.  Read Weiss, 2.5, then pp 114-115, where you can see an exception class written by Weiss.  Just change a few words and presto, you have the needed exception implementation.
  2. Need “throws…” in appropriate methods, and don’t forget @throws Javadoc too.
  3. Need to compose a BinCollection interface—that’s easy.  Note that SimpleBinCollection implements BinCollection.
  4. Write an alternative implementation for BinCollection: WorstFitBinCollection.
  5. Study your two implementations and determine what’s in common (probably both have an ArrayList, right?)
  6. Bump all the common stuff into an AbstractBinCollection class, leaving less in the two subclasses.  Use “protected” if private is too restricted.

End up with: using dotted lines for implements, more solid for extends:

          BinCollection interface
                  :
                  :
       AbstractBinCollection   abstract class with common code
              /         \
             /           \
     SimpleBinCollection  WorstFitBinCollection two concrete subclasses

 This is a good setup for the case of two implementations for one service described by an API, i.e., an interface.

Debugging

Basic ideas, not using a debugger (and thus universally usable)

  1. Add System.out.println(“addBox”);  to beginning of addBox, etc.  Get a trace of activity.
  2. Use toString yourself for debugging display.  To see Box b at a certain point, add in a new line:  System.out.println(“b = “ + b);  Here b gets cast to String via toString to satisfy concatenation. See pg. 37.
  3. To see the “this” object, same trick:  System.out.println(“in addBox, this = “ + this);
  4. To get a stack backtrace:  Thread.dumpStack();
  5. Any favorite tricks to share?

More advanced debugging, using the IDE's debugger: covered in lab 

Back to Chap. 5--study through pg. 186

Last time “finished” chap. 5, the parts we will cover.

Guide to Chap. 5:

5.1, 5.2—all

5.3—can skip, don’t worry about sigma notation (Σ)

5.4—just Big-Oh

5.5—log, important

5.6—binary search, important, except skip 5.6.3

5.7, 5.8—read

Note we are covering Big-Oh, but not the other Big’s and Little’s.

Working with arrays

Assign an element:  a[i] = 10   This is O(1) even for large i, because spot in array is computed by simple arithmetic.  Similarly accessing an array element.

Shifting elements down one to make a free spot in an array:

            for (i = n; i >= 5; i++)

                        a[i+1] = a[i]

This is n-5 passes each O(1), so T = O(n)

It’s fine to do this a few times, but if it’s in a bigger loop, it can get expensive.

For example, suppose each of n input items is placed somewhere in a growing array by making space for it this way.  Then for item j, it takes O(j) to insert it  For the whole thing, it costs O(1 + 2 +3 +  … + n) = O(n2).

There is a math formula 1 + 2 +3 +  … + n = n(n-1)/2.  that makes a neat proof for this.  But for our purposes, we can observe that the average value of the added items is n/2, and there are n of them, so the total must be O(n2).

pg. 181—more on logs

Note that "log" defaults to log base 2 here

Theorem 5.4  logB(N) = O(log N)  i.e., logs of all bases grow at the same rate for large N.

logB N =  log2 N / log2 B  =  log N / log B   so all log-bases are related by multiplicative constants, which we discard in Big-Oh analysis. 

For example, for B=10 ("common log"),  log2 (10) = 3.32,  so  log 10(N) = 3.32 * log (N)

Thus we can be apparently sloppy and say O(log N)  with a clear conscience.

Number Representation

8 bit integers—what are they called in Java?  Answer: type “byte”, not used much in ordinary apps.

MSB = most significant bit, shows sign of number

Zero and positive numbers:

0 = 00000000 in binary

1 = 00000001

2 = 00000010

…    ones advance left, until they have taken over all the bits except the MSB

? = 01111111  highest positive number, = 27 – 1 = 127

 

Negative numbers

-1 = 11111111

-2 = 11111110

-3 = 11111101

…        zeroes advance left, until they have taken over all the bits except the MSB

-? = 10000000  most negative number, = - 27 = -128

Full number of 8-bit integers = 1 +  (27 – 1)    + 27  = 2*27  = 28
                                         zero   positives  negatives

Range is [-128, 127]

Similarly--

16 bit integers, shorts in Java, have 215 – 1 positives, 1 zero, and 215 negatives, totaling 216 16-bit integers.  Range is [-32K, 32K-1]

32 bit integers, ints in Java, have 231 – 1 positives, 1 zero, and 231 negatives, totaling 232 32-bit integers.  Range is [-2G, 2G -1]

64 bit integers, longs in Java, have 263 – 1 positives, 1 zero, and 263 negatives, totaling 264 64-bit integers. Range is [-8192T, 8192T -1]

Important binary magnitudes:

kilo K =  210   =   1024, approx. 103

mega M =  220   =   10242, approx. 106

giga G = 230   =   10243, approx. 109

tera T = 240   =   10242, approx. 1012

We see that the number of n-bit numbers = 2n and thus the number of bits for N numbers is log2(N), very slowly growing with N.  If we add one more bit, we can represent twice as many numbers.

Section 5.6 Searching an Array for a value

Sequential Search

Suppose int array of length n:

for (i=0; i < a.length; i++)

   if (a[i] == x)

      return i;

We see the body is O(1), just array access, etc., and the number of passes is up to n, so the worst case performance is O(n).

OK for occasional use, but like shifting an array down one, not so good if it’s inside a loop.

Binary Search—much better, used in serious apps

Needs an ordered array.  Look at int array example, using code from Weiss, pg. 185 specialized to int array case.  Note that computing with an int array will be much faster than with an object array as required by the generic code, because the data is concentrated in memory in a tight array of int, not hung by references on a "spine" of reference spots.  With today's processors bringing in "cache lines" of say 64 bytes at a time from memory, this makes a real difference.

// ordered array of ints for binary search, set up in
// the caller of binSearch:

int[] a = { -10, -2, 5, 9, 50, 1000};
//           0    1  2  3  4   5

public static int binSearch( int [] a, int x)
{

... no time to fill in code

}

Example: Search for x = 5:, call binSearch(a, 5), get back return value of 2 because the value 5 sits at array spot 2.

Idea of binary search:  split the array into two halves, the low half and the high half of values, split by the middle value, say v.  Compare the target x with v, and if x is below v, it means that x is in the first half of the array, whereas if x is above v, it's in the high half, or else if v=x we found x already and we're done.  Then similarly process the half array we found.  Repeated halvings of the array quickly home in on the target.

Question: so what's the resulting T(N)?