NAME:

EE 322C Fall 2006 (Chase) Exam 1:

READ THIS FIRST. Please use the back side of each page for scratch paper. For some of the questions you may need to think quite a bit before you write down an answer. If you write while you think, use the back side of the page and copy your final (neatly written) answer to the front side. I will not give credit for illegible answers (and I reserve sole judgment for what is “legible”). The exam is out of 100 points, not all questions are equally hard or take equally long to complete. Some hard questions are not worth very much. Some easy questions are worth a lot. Good luck!

1. I’ve yet to meet him, but I’m certain there’s a “Chase Craig” out there. I’ve had some close calls. I’ve had a “Michael Craig” and a “Chase Krumpleman” as students, but never a “Chase Craig”. In this question you’ll be thinking about the problem of writing a program that detects pairs of names that are reverses of each other. Note that “Thomas Thomas” is a reverse of itself (and yes, I have had a Thomas Thomas as a student, a very smart guy by the way). a. (10 pts) For the first part of this question, you should write a function with O(N2) time complexity that counts and returns the number of names in a list that have a reverse. The list of names is passed to the function using two parameters. The first parameter is an array containing all the first names. The second parameter is an array containing all the last names. Note that the arrays are not sorted, but they are ordered. The kth person has his first name stored as the kth element in the first array and his last name stored as the kth element in the second array. int revs(String[] first, String[] last) { int N = first.length; int num_revs = 0; for (int k = 0; k < N; k += 1) { for (int j = 0; j < N; j += 1) { if (first[k].equals(last[j]) && last[k].equals(first[j])) { num_revs += 1; } } } return num_revs; } b. (5 pts) I found that the O(N2) algorithm seems to be bogging down for very large lists of names. If the algorithm runs in about one second on a list with 500 names, how long do you suppose it would run (approximately) if there were 1,000,000 names? (give your answer in seconds please). About 4 million seconds.

c. (15 pts) In an effort to improve the performance of my program, I’ve decided to put each name into a Pair class. The pair will have two data members. One data member will be the first name, and one will be the last name. I’ll then put all the names into one array (an array of Pairs) and sort the array. Assume I have a sort function already written, and that my sort function can sort an array of Comparable objects. Write the pair class so that my sort function will order the array by last name. If two people have the same last name, then my sort function should order those people by their first name. i.e., “Craig Chase, Eleanor Chase, Thomas Thomas” are in the correct order. You should not need know how the sort function works in order to answer this question. interface Comparable { // for your reference public int compareTo(Object that); } class Pair implements Comparable { String first; String last; public int compareTo(Object obj) { Pair that = (Pair) obj; if (last.compareTo(that.last) < 0) { return -1; } else if (last.compareTo(that.last) > 0) { return 1; } else { return first.compareTo(that.first); } } } d. (15 pts) Now that I can sort names, I’m rewriting my function. The function still has two parameters as before. However, now, I want to create a new array called names (an array of Pairs) and sort that array using the sort function. Next, I’ll create an array called swapped. I’ll copy all the Pairs from the other array into the new array. Then I’ll reverse the pairs (swapping their data members). Finally, I’ll sort the new array using the same sort function. My objective is to have two arrays, names and swapped where both arrays are sorted, names contains the original set of names (sorted by last name) and swapped contains the same names, but swapped such that they are effectively ordered by first name. Write this function for me. int revs2(String[] first, String[] last) { Pair[] names; Pair[] swapped;

int N = first.length; names = new Pair[N]; for (int k = 0; k < N; k += 1) { names[k] = new Pair(); names[k].first = first[k]; names[k].last = last[k]; }

swapped = new Pair[N]; for (int k = 0; k < N; k += 1) { swapped[k] = new Pair(); swapped[k].first = last[k]; swapped[k].last = first[k]; }

Arrays.sort(names, 0, N); Array.sort(swapped, 0, N);

return partE(names, swapped); // you’ll finish this function in partE } e. (10 pts) The last step of my program is to write the function that actually counts the number of matching names. Write this function for me. This function has two parameters. The first parameter is an array of pairs called names. This parameter contains all the names, and is sorted by last name. The second parameter is an array of pairs called swapped, and is sorted by last name as well (except, of course, the last name and first name have been swapped, so the last name is actually the first name). Your function must run in O(N) time, and must find the number of elements in the first array that are also present in the second array. int partE(Pair[] names, Pair[] swapped) { 2. In my continuing quest for world domination, I’ve written a network crawler that is scouring the internet gathering IP addresses for me. My current problem is storing all the IP addresses it collects. I want to keep the addresses in sequence (in the order they are collected), and I’m considering using either the LinkedList class or the ArrayList class to store the IP addresses. In this question, it will (eventually) be important to know that an IP address requires about eight bytes to store. It is also important to recognize that I do not know in advance how many IP addresses my crawler will find. It might be a few hundred, or it might be millions. a. For starters, I’m very concerned about the worst case time complexity of my program. After all, there might be millions of IP addresses that I need to store, in sequence. Assume the following. I have a function that reads IP addresses returned from the crawler. Each time it reads one IP address, it appends that address onto the end of my sequence. Assuming at some arbitrary point in time t I’ve collected N IP addresses. What’s the worst case time complexity for each of my data structure alternatives to create the first N elements in the sequence?

i. (5 pts) For the LinkedList my time complexity will be _____O(N)______

ii. (5 pts) For the ArrayList my time complexity will be ______O(N)______

b. (5 pts) I’m also concerned about the memory efficiency of my approach, after all, if I’m going to take over the world, I’ll need lots of computers. I know that the amortized doubling approach of ArrayList means that there will be wasted space, but I don’t know how much. If we assume that each IP address object takes eight bytes, and that each pointer (AKA reference) requires four bytes to store, how much memory (in the worst case) would be required to store N IP addresses in an ArrayList?

2N slots in the array, each slot is a pointer (4 bytes), so 8N bytes total for the array Plus N IP addresses, each IP address is eight bytes, so another 8N bytes. i.e., total space required for this data structure is 16N bytes c. My LinkedList does not suffer from the same wasted memory problem caused by amortized doubling (since linked lists never use amortized doubling). So, I’m leaning towards using the LinkedList. However, just for completeness, how much memory do you suppose would be required to store N IP addresses in a LinkedList? Recall that the LinkedList is doubly- linked, that each pointer (reference) requires 4 bytes to store, that an IP address requires eight bytes to store. Oh, and the JVM requires each object to have 4 bytes of meta-data (the type information). I included this extra 4 bytes in my 8-byte total size for IP addresses. i. (5 pts) Recall that the LinkedList is made up of a bunch of “cells”. How many bytes will be required for each cell? You might want to draw a picture here before answering your question, I’ll award partial credit for reasonable pictures.

16 bytes for each cell

ii. (5 pts) How many bytes will be required to store a linked list of N IP addresses?

N cells plus N IP address objects, = 24N bytes total

d. (5 pts) Finally, on the issue of execution speed, I’ve been told that Random-Access Memory isn’t (as in “RAM is not random access”). Thus, I’m concerned about the distance between objects on my linked list. If we assume that all the IP addresses are allocated ahead of time, and that once we start appending IP addresses to the Linked List, we do not do anything other than call the add function over and over (not very reasonable, but makes the math/analysis easier for this question, so work with me here), what will be the average distance spanned by the “next” pointer in the linked list? If I may be more specific…. What is the distance between the destination memory location of the next pointer (where it points to) and the next pointer itself (where it points from). You should assume a copy-based garbage collector as we discussed in class, and this question is multiple guess, choose one. i. The distance will be an arbtitrary random rumber. On average, the distance will be about ½ the size of the LinkedList ii. The distance will be an arbitrary random number. On average, the distance will be about ½ the amount of memory in the heap iii. The distance will always be a small number, probably about 4. iv. The distance will always be a large number, probably around N times the size of a list cell. 3. Consider the following classes, and indicate what the main program will print class Foo { int x; Foo () { x = 13; } public void doit() { System.out.println(x); } } class Bar extends Foo { Bar() { x = 14; } public void doit() { System.out.println(42); } } class FooBar extends Foo { int x; FooBar() { x = 15; } } class Question3 { public static void main(String[] why_do_I_need_this_stupid_param) { Foo x = new Foo(); Foo y = new Bar(); Foo z = new FooBar();

x.doit(); // (5 pts) prints: _____13______

y.doit(); // (5 pts) prints: ______42______

z.doit(); // (5 pts) prints: ______13______}