+ All Categories
Home > Documents > java book

java book

Date post: 14-Nov-2014
Category:
Upload: api-3836128
View: 915 times
Download: 1 times
Share this document with a friend
Popular Tags:
179
CS 61B: Data Structures (Spring 2002) Midterm I Solutions Problem 1. (6 points) Quickies. a. Another name for static fields is class variables. b. Advantages of a linked list over an array (any one will suffice): An item can be inserted at the beginning of a linked list without the need to move all the other items. The size of a linked list can always be increased by one quickly (specifically, in O(1) time) without ever taking the time to allocate and copy a whole array (which takes O(n) time). c. Advantages of an array over a linked list (any one will suffice): Any single item can be read or changed quickly (specifically, in O(1) time) simply by knowing its position in the array. An array takes less memory (by a constant factor) than a linked list to store the same number of items. d. Yes. myMethod can be overloaded by a second implementation of myMethod in MyClass that has a different signature. myMethod can be overrided by a third implementation of myMethod in a subclass of MyClass that has the same signature. Problem 2. (8 points) Inheritance. a. m returns 5 b. int i = ((XPlus) x).r();
Transcript
Page 1: java book

CS 61B: Data Structures (Spring 2002)

Midterm ISolutions

Problem 1. (6 points) Quickies.

a. Another name for static fields is class variables.

b. Advantages of a linked list over an array (any one will suffice):

An item can be inserted at the beginning of a linked list without the need to move all the other items.

The size of a linked list can always be increased by one quickly (specifically, in O(1) time) without ever taking the time to allocate and copy a whole array (which takes O(n) time).

c. Advantages of an array over a linked list (any one will suffice):

Any single item can be read or changed quickly (specifically, in O(1) time) simply by knowing its position in the array.

An array takes less memory (by a constant factor) than a linked list to store the same number of items.

d. Yes. myMethod can be overloaded by a second implementation of myMethod in MyClass that has a different signature. myMethod can be overrided by a third implementation of myMethod in a subclass of MyClass that has the same signature.

Problem 2. (8 points) Inheritance.

a. m returns 5

b. int i = ((XPlus) x).r();

c. return super.m();

d. The very last line of code causes a compile-time error. All the other lines compile and run without incident.

Problem 3. (5 points) Lists made of cons cells.

public static void main(String[] args) { Cons v = new Cons(); v.cdr = new Cons();

Page 2: java book

v.cdr.cdr = new Cons(); v.cdr.cdr.cdr = v.cdr; v.car = 2; v.cdr.car = 3; v.cdr.cdr.car = 9;}

Problem 4. (6 points) Loops made of cons cells.

public void breakLoop() { if (cdr != null) { if (cdr.car == -1) { cdr = null; } else { int i = car; car = -1; cdr.breakLoop(); car = i; } }}

Extra credit bonus point: Create a special Cons cell named dummyCons, which is not part of any list. Instead of marking Cons cells by setting car to -1, mark them by setting cdr to dummyCons.

Mail inquiries to [email protected]

Page 3: java book

CS 61B: Data Structures (Spring 2002)

Midterm IISolutions

Problem 1. (6 points) Quickies.

a. Theta(1) best-case time.

b. Theta(n) worst-case time.

c. Nodes J and P are pruned.

d.

Problem 2. (7 points) Binary Search Trees.

a. 3, 4, 5, and 6.

b. Advantages of a binary search tree over a hash table (any one will suffice):

Finding the smallest key greater than or equal to x is often faster. So is finding the smallest key, period. So is finding the largest key. So is finding the largest key less than or equal to x. Binary search trees don't need to be resized. A binary search tree allows you to print its contents in sorted order in linear time.

A hash table doesn't really. (You can sort the contents of a hash table with a linear-time sort, but that's obviously a lot more trouble.)

c. Do an inorder traversal of the tree. Return the kth node visited. (Note: we won't give full marks for a correct algorithm that isn't as asymptotically fast as this one.)

d. Theta(k + h) time. (Your answer may differ if you gave a slower algorithm for 2c. In that case, you may lose points on 2c for slowness but get full points here if you analyze your algorithm correctly.)

Page 4: java book

e. Do a standard BST findElement() operation, but use position fields in place of keys. (P.S. note that the position fields satisfy the binary search tree invariant.)

Problem 3. (7 points) Converting Directed Graphs to Undirected Graphs.

a.

public static void directedToUndirected(boolean[][] adjMatrix) { for (i = 0; i < adjMatrix.length; i++) { for (j = 0; j < adjMatrix.length; j++) { if (adjMatrix[i][j]) { adjMatrix[j][i] = true; } } }}

b. Theta(v2) time.

c. There are many possibilities. Here's the simplest one.

Problem 4. (5 points) Asymptotic Analysis.

Because f(n) is in Theta(j(n)), f(n) is in Omega(j(n)), so there exist positive constants c1, N1 such that

f(n) >= c1 j(n) for all n >= N1.

Similarly, because g(n) is in Theta(j(n)), g(n) is in O(j(n)), so there exist positive constants c2, N2 such that

g(n) <= c2 j(n) for all n >= N2.

Putting the two facts together, we find that

alpha f(n) - beta g(n) >= (alpha c1 - beta c2) j(n) for all n >= max{N1, N2}.

If you choose alpha and beta so that

alpha c1 - beta c2 > 0, it follows by the definition of big-Omega that alpha f(n) - beta g(n) is in Omega(j(n)). For example, you could choose alpha = 2/c1 and beta = 1/c2.

Page 6: java book

CS 61B: Data Structures (Spring 2000)

Midterm ISolutions

Problem 1. (6 points) Quickies.

a. The class with no superclass is Object.

b. An immutable object cannot be modified.

c.

d. The class MyHouse will compile if implementations are provided for both prototypes of throughTheRoof (each of which takes a different parameter).

e. Binary search begins by inspecting the middle element of a list or sublist thereof. If the list is linked, you will have to traverse half the nodes in the list/sublist to reach the middle one. Assuming you start traversing from the left end, it will take binary search just as long to reach any given node as it would take a naive search.

Problem 2. (12 points) Bug Hunt.

The compile-time errors and their fixes are as follows.

The field List.size is private, but the methods DList.copyList and DList.toDList change its value. size should be declared protected, or at least public or package.

In the abstract List class, the method toDList should be declared abstract. Alternatively, you could provide an implementation (which will always be overridden anyway).

Page 7: java book

The static method copyList attempts to use this, but this isn't defined in a static method. The line ``this.size = dbl.length();'' should read ``dbl.size = sngl.length();''. (The dbl-sngl mixup is my mistake, and we'll go easy on grading your correction to this line.)

The method DList.toDList tries to reference newList.head, but the static type of newList is List, and there's no head field in the class List. Here are two fixes.

o Change the declaration of newList: ``DList newList = new DList();''. o Cast newList: ``((DList) newList).head = head;''.

The logical errors are both in DList.copyList. The line of code that creates the sentinel doesn't create a sentinel that points to

itself. The line is ``dbl.head = new DListNode(null, dbl.head, dbl.head);''. When the DListNode constructor is called, the value of dbl.head is still null; dbl.head isn't assigned an object until after the constructor finishes executing. Hence, the prev and next fields of the sentinel are still null. (Many of you encountered this bug during Homework 4, and it was also discussed on the newsgroup. Lesson: read the newsgroup.)

One solution is to follow the dysfunctional line with the lines ``dbl.head.prev = dbl.head; dbl.head.next = dbl.head;''.

When a new node is inserted at the end of the doubly-linked list, the sentinel's prev pointer is not adjusted. The line ``oldTail.next = newNode;'' should be accompanied by the line ``dbl.head.prev = newNode;''.

Problem 3. (7 points) Condensing Alternate Pairs of Strings in a Singly-Linked List.

public void condense() { SListNode n = head; while (n != null) { if (n.next != null) { n.item = (String) n.item + (String) n.next.item; n.next = n.next.next; size--; } n = n.next; }}

Mail inquiries to [email protected]

Page 8: java book

CS 61B: Data Structures (Spring 2000)

Midterm ISolutions

Problem 1. (6 points) Quickies.

a. The class with no superclass is Object.

b. An immutable object cannot be modified.

c.

d. The class MyHouse will compile if implementations are provided for both prototypes of throughTheRoof (each of which takes a different parameter).

e. Binary search begins by inspecting the middle element of a list or sublist thereof. If the list is linked, you will have to traverse half the nodes in the list/sublist to reach the middle one. Assuming you start traversing from the left end, it will take binary search just as long to reach any given node as it would take a naive search.

Problem 2. (12 points) Bug Hunt.

The compile-time errors and their fixes are as follows.

The field List.size is private, but the methods DList.copyList and DList.toDList change its value. size should be declared protected, or at least public or package.

In the abstract List class, the method toDList should be declared abstract. Alternatively, you could provide an implementation (which will always be overridden anyway).

Page 9: java book

The static method copyList attempts to use this, but this isn't defined in a static method. The line ``this.size = dbl.length();'' should read ``dbl.size = sngl.length();''. (The dbl-sngl mixup is my mistake, and we'll go easy on grading your correction to this line.)

The method DList.toDList tries to reference newList.head, but the static type of newList is List, and there's no head field in the class List. Here are two fixes.

o Change the declaration of newList: ``DList newList = new DList();''. o Cast newList: ``((DList) newList).head = head;''.

The logical errors are both in DList.copyList. The line of code that creates the sentinel doesn't create a sentinel that points to

itself. The line is ``dbl.head = new DListNode(null, dbl.head, dbl.head);''. When the DListNode constructor is called, the value of dbl.head is still null; dbl.head isn't assigned an object until after the constructor finishes executing. Hence, the prev and next fields of the sentinel are still null. (Many of you encountered this bug during Homework 4, and it was also discussed on the newsgroup. Lesson: read the newsgroup.)

One solution is to follow the dysfunctional line with the lines ``dbl.head.prev = dbl.head; dbl.head.next = dbl.head;''.

When a new node is inserted at the end of the doubly-linked list, the sentinel's prev pointer is not adjusted. The line ``oldTail.next = newNode;'' should be accompanied by the line ``dbl.head.prev = newNode;''.

Problem 3. (7 points) Condensing Alternate Pairs of Strings in a Singly-Linked List.

public void condense() { SListNode n = head; while (n != null) { if (n.next != null) { n.item = (String) n.item + (String) n.next.item; n.next = n.next.next; size--; } n = n.next; }}

Mail inquiries to [email protected]

Page 10: java book

CS 61B: Data Structures (Spring 2000)

Midterm IISolutions

Problem 1. (7 points) Quickies.

a. The minimax algorithm could be said to be using either a preorder or a postorder tree traversal. (Either answer was accepted as correct.)

b. The maximum height of an n-node binary search tree is n - 1.

c. Pruning does not affect the answer produced by minimax.

d. x2z + xy.

e. Use two hash tables; one for authors and one for publishers.

f. None. Because of the finally clause, the only exception that can be thrown is a NullPointerException, which is unchecked.

Problem 2. (6 points) Data Structures.

a.

b.

Page 11: java book

c.

Problem 3. (4 points) Merging Trees.

Set T's root to be the root of R. Find the node in R with maximum key. Set that node's right child to be the root of S.

Problem 4. (8 points) Inserting a Key into a Binary Heap.

public void insertItem(int key) { int i = size + 1; while ((i > 1) && (key < heapArray[i / 2])) { heapArray[i] = heapArray[i / 2]; i = i / 2; } heapArray[i] = key; size++;}

Page 12: java book

Mail inquiries to [email protected] CS 61B Fall 1998 Final Exam Solutions

Problem 1:b.

7 9 / \ / \ 3 12 3 12 OR / \ / \ => / \ / \ 1 6 9 15 1 6 11 15 / \ / / / 5 11 14 5 14

6 / \ 3 12 / \ / \ 1 5 9 15 \ / 11 14

c.Theta(n), Omega(n), or 0(n)

d. Wf Xg

e. insert() may cause the array to run out of space.

f.Any sequence of operations that 1) Ends with the right keys in the tree and2) Ends with insert(2) or find(2) is correct

g.Worse: 19 bytesOnly in the latter case can the memory formerly occupied by W objects be reusedfor X objects.

Problem 2:a. X 3 4 5 5 12 8 9 7

Page 13: java book

b.

7 / \ 5 9 / \ \ 2 6 10 / \ 1 3

c.a b d c f g

E --->A<--------D<--------- | ^ | | | G | | / | / | / | B<--------C F

Problem 3:a. 5 8 1 0 7 3 9 53 8 1 0 7 5 9 5 3 0 1 8 7 5 9 53 0 1 5 7 5 9 80 3 1 5 7 5 9 80 1 3 5 7 5 9 80 1 3 5 7 5 8 90 1 3 5 5 7 8 9

b.One portion might get all the keys, the other portion none.

c.(i) Insertion sort: 2(ii) Selection sort: k(iii) Quicksort (array-based): k(iv) Radix sort: p

Problem 5:a.Walk through both lists in same order as merge step in mergesort.Write common elements to output list.O(s + t) = O(max{s, t})

b.For each item in T, check if it's in S (by binary search).Write common items to output array.O(t log s)

c.

Page 14: java book

For each item in SMALLER set, check if it's in larger set using hashtable. Write common item to output list & output hash table.O(min{s, t})

Problem 6:a. The nodes are stored on the stack.

b.Two possible answers:1. Put all red nodes (or green nodes, but not both) in the queue with a depth of zero. Mark them visited. Then continue running BFS as usual.2. Augment the graph with an extra vertex u, which has edges to every red vertex (or every green vertex, but not both). Run BFS starting from u.

Problem 7:a.Possible answers:1. Tree has extra field for minimum item. The end of every insert() or delete() calls the log-n version of findMin and stores the minimum item in the field.2. Tree has extra field for minimum item. Update on insert() is obvious. delete() takes us to the lower left leaf if we delete the minimum, so we can just look up the new minimum.3. Maintain pointer to leftmost leaf.

b.- Lists are doubly-linked- Objects have references to their locations in lists

c.Lazy deletion list can grow very long, so find() is not O(log n).

Problem 8:

public DSElement find() { if (parent == null) { return this; } parent = parent.find(); return parent; }

public void union(DSElement other) { DSElement thisRoot = this.find(); DSElement otherRoot = other.find(); if (thisRoot != otherRoot) { if (thisRoot.rank > otherRoot.rank) {

Page 15: java book

otherRoot.parent = thisRoot; } else { thisRoot.parent = otherRoot; if (thisRoot.rank == otherRoot.rank) { otherRoot.rank++; } } } }

Page 16: java book

CS 61B Spring 2000 Final Exam Solutions

Problem 1:b.

3 / \ 3 4 / \ / \ 5 6 4 8 / \ / \ 5 9 8 7

c.Omega(log n)

d.Theta(1)

e. y is in x's left subtree.

f.Theta(n) time, because of roving pointer.

g.If data you're still using is deallocated, new data may be written over it.

h. False

Problem 2:a.

9 OR 9 / \ / \ 2 10 2 10 / \ / \ 1 6 1 3 / \ \ 3 7 7 \ / \ 8 6 8

b.

Yes.

3 1

Page 17: java book

/ \ \ 2 4 findElement(1) 2 / \ -------------> \ 1 5 3

\ 4 \

5

c. (log n)k * ------- (log k)or

k log n (where log is base k) problem 3:a. 7 4 2 8 1 0 6 34 7 2 8 1 0 6 34 7 2 8 0 1 6 34 7 2 8 0 1 3 62 4 7 8 0 1 3 60 1 2 3 4 6 7 8

mergesort

b.7 4 2 8 1 0 6 30 4 2 8 1 7 6 30 1 2 8 4 7 6 30 1 2 3 4 7 6 80 1 2 3 4 6 7 8

selection sort

c.7 4 2 8 1 0 6 34 2 8 0 6 7 1 34 8 0 1 2 6 7 38 0 1 2 3 4 6 70 1 2 3 4 6 7 8

radix sort

d.7 4 2 8 1 0 6 34 7 2 8 1 0 6 3 2 4 7 8 1 0 6 31 2 4 7 8 0 6 30 1 2 4 7 8 6 30 1 2 4 6 7 8 3

Page 18: java book

0 1 2 3 4 6 7 8

insertion sort

e.

-Do not rotate the list to find a pivot; or if you do, rotate it back to its original state.-Do not remove pivot from list before partitioning.-Partition into 3 lists: less than pivot, equal to pivot (including pivot), greater than pivot. Sort first & last recursively.

Problem 4:

| || ____________ || | | || | ___ |<---------------------------------------\| |value | 7 | | | || | |___| | | || | ___ | | || |next |_--+-+--------\ || |____________| | | || | | || ____________ | | || | |<-------/ ______________ || | ___ | | | ____ | || |value | 3 | | | | value |_?__| | | | | |___| | | | ____ | | | | ___ | | | next | | | || |next | | | | | |_---+-+----/| | |_--+-|------------------->|______________|| |____________| | | ^ ^ || | | | HEAP|-----------|--|---|| main() | | || __ | | || x | -+--/ | || |__| | || __ | || y | -+-----/ || |__| ||__________________|

STACK

Problem 5:a.

2 5 / | \ / \

Page 19: java book

0 6 7 1 3 / / \ 9 4 8

b.

find(4)union(2, 5)find(8)

Final:

-----2------- / / | \ \ \ 0 6 7 5 3 8 | / \ 9 1 4

c.Scan through array, find all children of ITEM. If ITEM is not root, make ITEM'schildren point to its parent. If ITEM is a root, choose arbitrary child to benew root; make other children point to it.

d.One possibility:Use a general sibling-based tree data structure, but make siblings bedoubly-linked so path compression is fast.

Another possibility:Each set's root references a linked list of all the items in the set (whichdoes NOT need to be doubly linked). When sets are unioned, these lists areconcatenated. isolate() walks through the list to find all children of item(and also removes item from the list).

Problem 6:a. No. x is passed by value, cannot be changed.Strings are immutable.

b.Yes.x may be a class variable (static) or object field accessible to foo(), so xcan be changed by foo().

c.

Page 20: java book

Yes.x may be passed by reference.

Problem 7:a.O(log x + log y + x/y)

b.f(n) is in O(n sqrt(n)): n n Sum (sqrt(i)) <= Sum (sqrt(n)) = n sqrt(n) is in O(n sqrt(n)) by choosing i=1 i=1

c = 1 and N = any constant.

f(n) is in Omega(n sqrt(n)):

n n n Sum (sqrt(i)) >= Sum (sqrt(i)) >= Sum (sqrt(ceil(n/2))) >= i=1 i=ceil(n/2) i=ceil(n/2)

ceil(n/2) sqrt(ceil(n/2)) >= (n/2) sqrt(n/2) = [n sqrt(n)] / [2 sqrt(2)].

[n sqrt(n)] / [2 sqrt(2)] is in Omega(n sqrt(n)) by choosingd = 1 / [2 sqrt(2)] or smaller and N = any constant.

OR

by showing n sqrt(n) is in O([n sqrt(n)] / [2 sqrt(2)]) by choosingc = 2 sqrt(2) or larger and N = any constant.

Problem 8:

int[] counts = new int[range];for (int i = 0; i < sortMe.length; i++) { counts[sortMe[i]]++;}

int index = 0;for (int i = 0; i < range; i++) { for (int j = 0; j < counts[i]; j++) { sorted[index] = i; index++; }}

CS 61B: Practice for the Final Exam

Page 21: java book

We will cover some of these questions for review, but please attempt thesequestions before that comes to pass. Starred problems are particularlydifficult.

Warning: Midterm 1 topics are absent here, but will reappear on the final.

[1] Given an array containing the digits 71808294, show how the order of the digits changes during each step of [a] insertion sort, [b] selection sort, [c] mergesort, [d] quicksort (using the array-based quicksort of Lecture 31, and always choosing the last element of any subarray to be the pivot), and [e] heapsort (using the backward min-heap version discussed in Lecture 30). Show the array after each swap, except in insertion sort. For insertion sort, show the array after each insertion.

[2] Some sorting methods, like heapsort and array-based quicksort, are not naturally stable. Suggest a way to make _any_ sorting algorithm stable by extending the keys (making them longer and adding extra information).

[3] Consider the graph at right. e f |17 |15 [a] In what order are the vertices visited using DFS | | starting from vertex a? Where a choice exists, use 3 | 9 | 1 alphabetical order. What if you use BFS? a---c---g---h [b] A vertex x is "finished" when the recursive call | | | / DFS(x) terminates. In what order are the vertices |7 9| 11| /5 finished? (This is different from the order in | | |/ which they are visited, when DFS(x) is called.) b---d---i [c] In what order are edges added to the minimum 12 14 spanning tree by Kruskal's algorithm? List the edges by giving their endpoints.

[4] [a] How long does it take to determine if an undirected graph contains a vertex that is connected to no other vertices [i] if you use an

Page 22: java book

adjacency matrix; [ii] if you use adjacency lists. [b] Suppose we use DFS on a binary search tree, starting from the root. The edge to a left child is always traversed before an edge to the right child. In what order are the nodes visited? Finished? [c] An undirected graph contains a "cycle" (i.e., loop) if there are two different simple paths by which we can get from one vertex to another. Using breadth-first search (not DFS), how can we tell if an undirected graph contains a cycle? [d] Recall that an undirected graph is "connected" if there is a path from any vertex to any other vertex. If an undirected graph is not connected, it has multiple connected components. A "connected component" consists of all the vertices reachable from a given vertex, and the edges incident on those vertices. Suggest an algorithm based on DFS (possibly multiple invocations of DFS) that counts the number of connected components in a graph.

[5] What does the splay tree at right look like after: 3 / \ [a] maxElement() 1 5 /\ /\ [b] insertItem(4.5) \ 0 2 4 11 | Start from the _original_ tree, / \ [c] findElement(10) | not the tree resulting from the 7 12 | previous operation. / \ [d] remove(9) / 6 9 / \ 8 10

[6] Consider the quick-union algorithm for disjoint sets. We know that a sequence of n operations (unions and finds) can take asymptotically slightly more than linear time in the worst case.

[a] Explain why if all the finds are done before all the unions, a sequence of n operations is guaranteed to take O(n) time. [b] Explain why if all the unions are done before all the finds, a * sequence of n operations is guaranteed to take O(n) time. -----

Page 23: java book

[7] [a] Suggest a sequence of insertion operations 4 |3 5| that would create the binary tree at right. / \ ----- [b] Suggest a sequence of operations that would 2 6 / | \ create the 2-3-4 tree at right. You are / \ ----- --- --- allowed to use removal as well as insertion. 1 3 |1 2| |4| |6| ----- --- ---

[8] Suppose an application uses only three operations: insertItem(), findElement(), and remove().

[a] Under what circumstances would you use a splay tree instead of a hash table? [b] Under what circumstances would you use a 2-3-4 tree instead of a splay tree? [c] Under what circumstances would you use an unordered array instead of a 2-3-4 tree? [d] Under what circumstances would you use a binary heap instead of an unordered array?

[9] [a] Suppose we are implementing a binary heap, based on reference-based * binary trees (_not_ arrays). We want to implement a deleteRef() operation which, given a _reference_ to a node in the tree, can delete that node (and the item it contains) from the heap while maintaining the heap-order property--even if the node isn't the root and its item isn't the minimum. deleteRef() should run in O(log n) time. How do we do it? [b] Building on your answer to the previous question, explain how to combine a min-heap and max-heap (both using reference-based binary trees) to yield a data structure that implements insertItem(), deleteMin(), and deleteMax() in O(log n) time. Hint: You will need inter-heap pointers. Think of how you deleted edges in Project 3, for example. [c] How can we accomplish the same thing if we use array-based heaps? Hint: Add an extra field to the items stored in each array.

Page 24: java book

[10] Recall that the linked-list version of quicksort() puts all items whose * keys are equal to the pivot's key into a third queue, which doesn't need to be sorted. This can save much time if there are many repeated keys. The array-based version of quicksort() does not treat items with equal keys specially, so those items are sorted in the recursive calls.

Is it possible to modify array-based quicksort() so that the array is partitioned into three parts (keys less than pivot, keys equal to pivot, keys greater than pivot) while still being in-place? (The only memory you may use is the array plus a constant amount of additional memory.) Why or why not?

[11] Suppose we wish to create a binary heap containing the keys D A T A S T R U C T U R E. (All comparisons use alphabetical order.)

[a] Show the resulting min-heap if we build it using successive insertItem() operations (starting from D).

[b] Show the resulting min-heap if we build it using bottomUpHeap().

[12] Suppose we modify the array-based quicksort() implementation in the Lecture 31 notes to yield an array-based quickselect() algorithm, as described in Lecture 35. Show the steps it would use to find the median letter in D A T A S T R U C T U R E. (The median in this case is the 7th letter, which would appear at array index 6 if we sorted the letters.) As in Question [1], choose the last element of any subarray to be the pivot, and show the array after each swap.

[13] C++ objects can be declared on the stack, on the heap, or in static storage, just like structures. Consider the following C++ code.

class ListNode { | void dumbRoutine(int i, int j) { public: | int number; | List myList; ListNode *next; | ListNode node2; }; | | myList.head = new ListNode(); class List { | myList.head->number = i; public: | myList.head->next = &node2; ListNode *head; | myList.head->next->number = j;

Page 25: java book

} | }

[a] If a program calls dumbRoutine() frequently, is the program certain to suffer from a memory leak? [b] If a program calls dumbRoutine() frequently, is the program thereby susceptible to having some of its data inadvertently corrupted? [c] If the declaration "List myList;" is moved outside of dumbRoutine(), so that myList is a global variable, the answers to both [a] and [b] change. Explain why.

[14] What's wrong with this heap allocation strategy? We keep all allocated chunks on the heap contiguous. Whenever a free() or delete operation occurs, we find the position of the newly freed chunk, then we move all the chunks to the right of it leftward to fill the gap. That way, no fragmentation occurs at all! Allocation requests are satisfied using the first free memory, to the right of all the allocated chunks.

--------------------------------- --------------------------------- |&&***&&*******&&**&&****&&...... => |&&***&&**&&****&&............... --------------------------------- --------------------------------- ^free()

[15] What are the values of the four elements of the array x after the following C code is executed?

int x[4]; int *p; p = &x[1]; p[2] = 20; p = &p[1]; *p = 8; *x = 33;

[16] Suppose our radix-sort algorithm takes exactly n+r seconds per pass, where n is the number of keys to sort, and r is the radix (number of queues). To sort 493 keys, what radix r will give us the best running time? With this radix, how many passes will it take to sort 420-bit keys? To answer this question, you'll need to use calculus (and a calculator), and you'll need to remember that log2 r = (ln r) / (ln 2).

Page 26: java book

[17] Suppose that while your computer is sorting an array of objects, its memory is struck by a cosmic ray that changes exactly one of the keys to something completely different. For each of the following sorting algorithms, what is the _worst-case_ possibility? For each, answer [x] the final array won't even be close to sorted, [y] the final array will have just one or two keys out of place, or [z] the final array will consist of two separate sorted subsets, one following the other, plus perhaps one or two additional keys out of place.

[a] Insertion sort [b] Selection sort [c] Mergesort [d] Radix sort

Programming questions.

[18] Rewrite the quicksort() method from the Lecture 31 notes in C++. The signature should appear as follows.

void quicksort(Comparable *a, int length) {

Note one big change from the Java version: instead of passing an array, a low index, and a high index, we pass only an array and its length (the number of items to be sorted). The call above should sort the elements a[0] through a[length - 1]. The reason only two parameters are needed for the recursion is because the Java call quicksort(a, x, y) can be replaced by the C++ call quicksort(&a[x], y-x+1). Be careful to make sure that your array indices are correct in your C++ version.

[19] Implement tree sort (as described in the sorting video) in Java. Assume your treeSort() method's only input parameters are the number of items and a complete (perfectly balanced) BinaryTree of depth d in which each leaf has an item; hence, there are 2^d items to sort. All internal nodes begin with their item field set to null. Use the data structures below (in which each node knows its left and right child), not a general tree.

Page 27: java book

Your algorithm should never change a node reference; only the items move. The centerpiece of your algorithm will be a method that fills an empty node by (i) recursively filling its left and right children if they're empty, and (ii) choosing the smaller of its children's items, which is moved up into the empty node. treeSort() will repeatedly: (i) apply this method to the root node to find the smallest item remaining in the tree, (ii) pluck that item out of the root node, leaving the root empty again, and (iii) put the item into an array. Your treeSort() should allocate and return that array.

class BinaryTreeNode { | class BinaryTree { Comparable item; | BinaryTreeNode root; BinaryNode leftChild; | } BinaryNode rightChild; | } |

/* OpenCommercial.java */

import java.net.*;import java.io.*;

Page 28: java book

/** A class that provides a main function to read five lines of a commercial * Web page and print them in reverse order, given the name of a company. */

class OpenCommercial {

/** Prompts the user for the name X of a company (a single string), opens * the Web site corresponding to www.X.com, and prints the first five lines * of the Web page in reverse order. * @param arg is not used. * @exception Exception thrown if there are any problems parsing the * user's input or opening the connection. */ public static void main(String[] arg) throws Exception {

BufferedReader keyboard; String inputLine;

keyboard = new BufferedReader(new InputStreamReader(System.in));

System.out.print("Please enter the name of a company (without spaces): "); System.out.flush(); /* Make sure the line is printed immediately. */ inputLine = keyboard.readLine();

/* Replace this comment with your solution to Problem 1 on page 81. */

}}

/* Date.java */

import java.io.*;

class Date {

/* Put your private data fields here. */

Page 29: java book

/** Constructs a date with the given month, day and year. If the date is * not valid, the entire program will halt with an error message. * @param month is a month, numbered in the range 1...12. * @param day is between 1 and the number of days in the given month. * @param year is the year in question, with no digits omitted. */ public Date(int month, int day, int year) {

}

/** Constructs a Date object corresponding to the given string. * @param s should be a string of the form "month/day/year" where month must * be one or two digits, day must be one or two digits, and year must be * between 1 and 4 digits. If s does not match these requirements or is not * a valid date, the program halts with an error message. */ public Date (String s) {

}

/** Checks whether the given year is a leap year. * @returns true if and only if the input year is a leap year. */ public static boolean isLeapYear(int year) { return true; // replace this line with your solution }

/** Returns the number of days in a given month. * @param month is a month, numbered in the range 1...12. * @param year is the year in question, with no digits omitted. * @return the number of days in the given month. */ public static int daysInMonth(int month, int year) { return 0; // replace this line with your solution }

/** Checks whether the given date is valid. * @return true if and only if month/day/year constitute a valid date. */ public static boolean isValidDate(int month, int day, int year) { return true; // replace this line with your solution }

/** Returns a string representation of a date in the form month/day/year. * The month, day, and year are printed in full as integers; for example, * 12/7/1998 or 3/21/407.

Page 30: java book

* @return a String representation of the date. */ public String toString() { return "stuff"; // replace this line with your solution }

/** Determines whether this Date is before the Date d. * @return true if and only if this Date is before d. */ public boolean isBefore(Date d) { return true; // replace this line with your solution }

/** Determines whether this Date is after the Date d. * @return true if and only if this Date is after d. */ public boolean isAfter(Date d) { return true; // replace this line with your solution }

/** Returns the number of this Date in the year. * @return a number n in the range 1...366, inclusive, such that this Date * is the nth day of its year. (366 is only used for December 31 in a leap * year.) */ public int dayInYear() { return 0; // replace this line with your solution }

/** Determines the difference in days between d and this Date. For example, * if this Date is 12/15/1997 and d is 12/14/1997, the difference is 1. * If this Date occurs before d, the result is negative. * @return the difference in days between d and this date. */ public int difference(Date d) { return 0; // replace this line with your solution }

public static void main (String[] argv) { System.out.println("\nTesting constructors."); Date d1 = new Date(1, 1, 1); System.out.println("Date should be 1/1/1: " + d1); d1 = new Date("2/4/2"); System.out.println("Date should be 2/4/2: " + d1); d1 = new Date("2/29/2000"); System.out.println("Date should be 2/29/2000: " + d1); d1 = new Date("2/29/1904"); System.out.println("Date should be 2/29/1904: " + d1);

Page 31: java book

d1 = new Date(12, 31, 1975); System.out.println("Date should be 12/31/1975: " + d1); Date d2 = new Date("1/1/1976"); System.out.println("Date should be 1/1/1976: " + d2); Date d3 = new Date("1/2/1976"); System.out.println("Date should be 1/2/1976: " + d3);

Date d4 = new Date("2/27/1977"); Date d5 = new Date("8/31/2110");

/* I recommend you write code to test the isLeapYear function! */

System.out.println("\nTesting before and after."); System.out.println(d2 + " after " + d1 + " should be true: " + d2.isAfter(d1)); System.out.println(d3 + " after " + d2 + " should be true: " + d3.isAfter(d2)); System.out.println(d1 + " after " + d1 + " should be false: " + d1.isAfter(d1)); System.out.println(d1 + " after " + d2 + " should be false: " + d1.isAfter(d2)); System.out.println(d2 + " after " + d3 + " should be false: " + d2.isAfter(d3));

System.out.println(d1 + " before " + d2 + " should be true: " + d1.isBefore(d2)); System.out.println(d2 + " before " + d3 + " should be true: " + d2.isBefore(d3)); System.out.println(d1 + " before " + d1 + " should be false: " + d1.isBefore(d1)); System.out.println(d2 + " before " + d1 + " should be false: " + d2.isBefore(d1)); System.out.println(d3 + " before " + d2 + " should be false: " + d3.isBefore(d2));

System.out.println("\nTesting difference."); System.out.println(d1 + " - " + d1 + " should be 0: " + d1.difference(d1)); System.out.println(d2 + " - " + d1 + " should be 1: " + d2.difference(d1)); System.out.println(d3 + " - " + d1 + " should be 2: " + d3.difference(d1)); System.out.println(d3 + " - " + d4 + " should be -422: " + d3.difference(d4)); System.out.println(d5 + " - " + d4 + " should be 48762: " + d5.difference(d4)); }}

Page 32: java book

/* Date.java */

import java.io.*;

class Date {

/* Put your private data fields here. */

/** Constructs a date with the given month, day and year. If the date is * not valid, the entire program will halt with an error message. * @param month is a month, numbered in the range 1...12. * @param day is between 1 and the number of days in the given month. * @param year is the year in question, with no digits omitted. */ public Date(int month, int day, int year) {

}

/** Constructs a Date object corresponding to the given string. * @param s should be a string of the form "month/day/year" where month must * be one or two digits, day must be one or two digits, and year must be * between 1 and 4 digits. If s does not match these requirements or is not * a valid date, the program halts with an error message. */ public Date (String s) {

}

/** Checks whether the given year is a leap year. * @returns true if and only if the input year is a leap year. */ public static boolean isLeapYear(int year) { return true; // replace this line with your solution }

/** Returns the number of days in a given month. * @param month is a month, numbered in the range 1...12. * @param year is the year in question, with no digits omitted. * @return the number of days in the given month. */ public static int daysInMonth(int month, int year) { return 0; // replace this line with your solution }

/** Checks whether the given date is valid. * @return true if and only if month/day/year constitute a valid date. */ public static boolean isValidDate(int month, int day, int year) {

Page 33: java book

return true; // replace this line with your solution }

/** Returns a string representation of a date in the form month/day/year. * The month, day, and year are printed in full as integers; for example, * 12/7/1998 or 3/21/407. * @return a String representation of the date. */ public String toString() { return "stuff"; // replace this line with your solution }

/** Determines whether this Date is before the Date d. * @return true if and only if this Date is before d. */ public boolean isBefore(Date d) { return true; // replace this line with your solution }

/** Determines whether this Date is after the Date d. * @return true if and only if this Date is after d. */ public boolean isAfter(Date d) { return true; // replace this line with your solution }

/** Returns the number of this Date in the year. * @return a number n in the range 1...366, inclusive, such that this Date * is the nth day of its year. (366 is only used for December 31 in a leap * year.) */ public int dayInYear() { return 0; // replace this line with your solution }

/** Determines the difference in days between d and this Date. For example, * if this Date is 12/15/1997 and d is 12/14/1997, the difference is 1. * If this Date occurs before d, the result is negative. * @return the difference in days between d and this date. */ public int difference(Date d) { return 0; // replace this line with your solution }

public static void main (String[] argv) {

Page 34: java book

System.out.println("\nTesting constructors."); Date d1 = new Date(1, 1, 1); System.out.println("Date should be 1/1/1: " + d1); d1 = new Date("2/4/2"); System.out.println("Date should be 2/4/2: " + d1); d1 = new Date("2/29/2000"); System.out.println("Date should be 2/29/2000: " + d1); d1 = new Date("2/29/1904"); System.out.println("Date should be 2/29/1904: " + d1);

d1 = new Date(12, 31, 1975); System.out.println("Date should be 12/31/1975: " + d1); Date d2 = new Date("1/1/1976"); System.out.println("Date should be 1/1/1976: " + d2); Date d3 = new Date("1/2/1976"); System.out.println("Date should be 1/2/1976: " + d3);

Date d4 = new Date("2/27/1977"); Date d5 = new Date("8/31/2110");

/* I recommend you write code to test the isLeapYear function! */

System.out.println("\nTesting before and after."); System.out.println(d2 + " after " + d1 + " should be true: " + d2.isAfter(d1)); System.out.println(d3 + " after " + d2 + " should be true: " + d3.isAfter(d2)); System.out.println(d1 + " after " + d1 + " should be false: " + d1.isAfter(d1)); System.out.println(d1 + " after " + d2 + " should be false: " + d1.isAfter(d2)); System.out.println(d2 + " after " + d3 + " should be false: " + d2.isAfter(d3));

System.out.println(d1 + " before " + d2 + " should be true: " + d1.isBefore(d2)); System.out.println(d2 + " before " + d3 + " should be true: " + d2.isBefore(d3)); System.out.println(d1 + " before " + d1 + " should be false: " + d1.isBefore(d1)); System.out.println(d2 + " before " + d1 + " should be false: " + d2.isBefore(d1)); System.out.println(d3 + " before " + d2 + " should be false: " + d3.isBefore(d2));

System.out.println("\nTesting difference."); System.out.println(d1 + " - " + d1 + " should be 0: " + d1.difference(d1)); System.out.println(d2 + " - " + d1 + " should be 1: " + d2.difference(d1)); System.out.println(d3 + " - " + d1 + " should be 2: " + d3.difference(d1)); System.out.println(d3 + " - " + d4 + " should be -422: " + d3.difference(d4)); System.out.println(d5 + " - " + d4 + " should be 48762: " + d5.difference(d4)); }

Page 35: java book

}

/* SList.java */

/** * The SList class is a singly-linked implementation of the linked list * abstraction. SLists are mutable data structures, which can grow at either * end. * * @author Kathy Yelick and Jonathan Shewchuk **/

public class SList {

private SListNode head; private int size;

/** * SList() constructs an empty list. **/

public SList() { size = 0; head = null; }

/** * isEmpty() indicates whether the list is empty. * @return true if the list is empty, false otherwise. **/

public boolean isEmpty() { return size == 0; }

/** * length() returns the length of this list. * @return the length of this list. **/

public int length() { return size; }

/** * insertFront() inserts item "obj" at the beginning of this list. * @param obj the item to be inserted. **/

public void insertFront(Object obj) { head = new SListNode(obj, head);

Page 36: java book

size++; }

/** * insertEnd() inserts item "obj" at the end of this list. * @param obj the item to be inserted. **/

public void insertEnd(Object obj) { if (head == null) { head = new SListNode(obj); } else { SListNode node = head; while (node.next != null) { node = node.next; } node.next = new SListNode(obj); } size++; }

/** * nth() returns the item at the specified position. If position < 1 or * position > this.length(), null is returned. Otherwise, the item at * position "position" is returned. The list does not change. * @param position the desired position, from 1 to length(), in the list. * @return the item at the given position in the list. **/

public Object nth(int position) { SListNode currentNode;

if ((position < 1) || (head == null)) { return null; } else { currentNode = head; while (position > 1) { currentNode = currentNode.next; if (currentNode == null) { return null; } position--; } return currentNode.item; } }

/** * squish() takes this list and, wherever two or more consecutive items are * equal(), it removes duplicate nodes so that only one consecutive copy * remains. Hence, no two consecutive items in this list are equal() upon

Page 37: java book

* completion of the procedure. * * After squish() executes, the list may well be shorter than when squish() * began. No extra items are added to make up for those removed. * * For example, if the input list is [ 0 0 0 0 1 1 0 0 0 3 3 3 1 1 0 ], the * output list is [ 0 1 0 3 1 0 ]. * * Unlike with "smoosh()", "this" list is modified. * * IMPORTANT: Be sure you use the equals() method, and not the "==" * operator, to compare items. **/

public void squish() { // Fill in your solution here. (Ours is eleven lines long.) }

/** * twin() takes this list and doubles its length by replacing each node * with two consecutive nodes referencing the same item. * * For example, if the input list is [ 3 7 4 2 2 ], the * output list is [ 3 3 7 7 4 4 2 2 2 2 ]. * * IMPORTANT: Do not try to make new copies of the items themselves. * Just copy the references to the items. **/

public void twin() { // Fill in your solution here. (Ours is seven lines long.) }

/** * toString() converts the list to a String. * @return a String representation of the list. **/

public String toString() { int i; Object obj; String result = "[ ";

SListNode cur = head;

while (cur != null) { obj = cur.item; result = result + obj.toString() + " "; cur = cur.next; } result = result + "]"; return result; }

Page 38: java book

/** * main() runs test cases on the SList class. Prints summary * information on basic operations and halts with an error (and a stack * trace) if any of the tests fail. **/

public static void main (String[] args) { testEmpty(); testAfterInsertFront(); testAfterInsertEnd(); }

/** * testEmpty() tests toString(), isEmpty(), length(), insertFront(), and * insertEnd() on an empty list. Prints summary information of the tests * and halts the program if errors are detected. **/

private static void testEmpty() { SList lst1 = new SList(); SList lst2 = new SList(); System.out.println(); System.out.println("Here is a list after construction: "

+ lst1.toString()); TestHelper.verify(lst1.toString().equals("[ ]"),

"toString on newly constructed list failed");

System.out.println("isEmpty() should be true. It is: " + lst1.isEmpty());

TestHelper.verify(lst1.isEmpty() == true, "isEmpty() on newly constructed list failed");

System.out.println("length() should be 0. It is: " + lst1.length());

TestHelper.verify(lst1.length() == 0, "length on newly constructed list failed");

lst1.insertFront(new Integer(3)); System.out.println("Here is a list after insertFront(3) to an empty list: "

+ lst1.toString()); TestHelper.verify(lst1.toString().equals("[ 3 ]"),

"InsertFront on empty list failed"); lst2.insertEnd(new Integer(5)); System.out.println("Here is a list after insertEnd(5) on an empty list: "

+ lst2.toString()); TestHelper.verify(lst2.toString().equals("[ 5 ]"),

"insertEnd on empty list failed"); }

/** * testAfterInsertFront() tests toString(), isEmpty(), length(),

Page 39: java book

* insertFront(), and insertEnd() after insertFront(). Prints summary * information of the tests and halts the program if errors are detected. **/

private static void testAfterInsertFront() { SList lst1 = new SList(); lst1.insertFront(new Integer(3)); lst1.insertFront(new Integer(2)); lst1.insertFront(new Integer(1)); System.out.println(); System.out.println("Here is a list after insertFront 3, 2, 1: "

+ lst1.toString()); TestHelper.verify(lst1.toString().equals("[ 1 2 3 ]"),

"InsertFronts on non-empty list failed"); System.out.println("isEmpty() should be false. It is: " +

lst1.isEmpty()); TestHelper.verify(lst1.isEmpty() == false,

"isEmpty() after insertFront failed"); System.out.println("length() should be 3. It is: " +

lst1.length()); TestHelper.verify(lst1.length() == 3,

"length() after insertFront failed"); lst1.insertEnd(new Integer(4)); System.out.println("Here is the same list after insertEnd(4): "

+ lst1.toString()); TestHelper.verify(lst1.toString().equals("[ 1 2 3 4 ]"),

"insertEnd on non-empty list failed"); } /** * testAfterInsertEnd() tests toString(), isEmpty(), length(), * insertFront(), and insertEnd() after insertEnd(). Prints summary * information of the tests and halts the program if errors are detected. **/

private static void testAfterInsertEnd() { SList lst1 = new SList(); lst1.insertEnd(new Integer(6)); lst1.insertEnd(new Integer(7)); System.out.println(); System.out.println("Here is a list after insertEnd 6, 7: "

+ lst1.toString()); System.out.println("isEmpty() should be false. It is: " +

lst1.isEmpty()); TestHelper.verify(lst1.isEmpty() == false,

"isEmpty() after insertEnd failed"); System.out.println("length() should be 2. It is: " +

lst1.length()); TestHelper.verify(lst1.length() == 2,

"length() after insertEndfailed"); lst1.insertFront(new Integer(5)); System.out.println("Here is the same list after insertFront(5): "

+ lst1.toString()); TestHelper.verify(lst1.toString().equals("[ 5 6 7 ]"),

Page 40: java book

"insertFront after insertEnd failed"); }}

/* SListNode.java */

/** * SListNode is a class used internally by the SList class. An SList object * is a singly-linked list, and an SListNode is a node of a singly-linked * list. Each SListNode has two references: one to an object, and one to * the next node in the list. * * @author Kathy Yelick and Jonathan Shewchuk */

class SListNode { Object item; SListNode next;

/** * SListNode() (with one parameter) constructs a list node referencing the * item "obj". */

SListNode(Object obj) { item = obj; next = null; }

/** * SListNode() (with two parameters) constructs a list node referencing the * item "obj", whose next list node is to be "next". */

SListNode(Object obj, SListNode next) { item = obj; this.next = next; }

}

Page 41: java book

/* TestHelper.java */

/** * This class is based on code from Arnow and Weiss. Its verify() method * exits with an error message if an invariant fails to hold true. * * The purpose of this class is to provide a shorthand for writing and testing * invariants in any program. **/

public class TestHelper {

/** * verify() checks an invariant and prints an error message if it fails. * If invariant is true, this method does nothing. If invariant is false, * the message is printed, followed by a dump of the program call stack. * @param invariant the condition to be verified * @param message the error message to be printed if the invariant fails to * hold true. **/

static void verify(boolean invariant, String message) { if (!invariant) { System.out.println("*** ERROR: " + message); Thread.dumpStack(); } }

}

Page 42: java book

/* Ocean.java */

/** * The Ocean class defines an object that models an ocean full of sharks and * fish. Descriptions of the methods you must implement appear below. They * include a constructor of the form * * public Ocean(int i, int j, int starveTime); * * that creates an empty ocean having width i and height j, and the specified * shark starveTime. * * See the README file accompanying this project for additional details. */

public class Ocean {

/* You may renumber these constants if you wish, but don't rename them. */

public final static int EMPTY = 0; public final static int SHARK = 1; public final static int FISH = 2;

/** * Define any variables associated with an Ocean object here. These * variables MUST be private. */

/** * The following methods are required for Part I. */

/** * Ocean() is a constructor that creates an empty ocean having width i, * height j, and the specified shark starveTime. */

public Ocean(int i, int j, int starveTime) { // Your solution here. }

Page 43: java book

/** * width() returns the width of an Ocean object. * @return the width of the ocean. */

public int width() { // Replace the following line with your solution. return 1; }

/** * height() returns the height of an Ocean object. * @return the height of the ocean. */

public int height() { // Replace the following line with your solution. return 1; }

/** * starveTime() returns the shark starveTime of an Ocean object. * @return the shark starveTime. */

public int starveTime() { // Replace the following line with your solution. return 1; }

/** * addFish() places a fish in cell (x, y) if the cell is empty. If the * cell is already occupied, leave the cell as it is. * @param x is the x-coordinate of the cell to place a fish in. * @param y is the y-coordinate of the cell to place a fish in. */

public void addFish(int x, int y) { // Your solution here. }

/** * addShark() (with two parameters) places a newborn shark in cell (x, y) if * the cell is empty. A "newborn" shark is equivalent to a shark that has * just eaten. If the cell is already occupied, leave the cell as it is. * @param x is the x-coordinate of the cell to place a shark in. * @param y is the y-coordinate of the cell to place a shark in. */

public void addShark(int x, int y) { // Your solution here. }

Page 44: java book

/** * cellContents() returns EMPTY if cell (x, y) is empty, FISH if it contains * a fish, and SHARK if it contains a shark. * @param x is the x-coordinate of the cell whose contents are queried. * @param y is the y-coordinate of the cell whose contents are queried. */

public int cellContents(int x, int y) { // Replace the following line with your solution. return EMPTY; }

/** * timeStep() performs a simulation timestep as described in README. * @return an ocean representing the elapse of one timestep. */

public Ocean timeStep() { // Replace the following line with your solution. return new Ocean(1, 1, 1); }

/** * The following method is required for Part II. */

/** * addShark() (with three parameters) places a shark in cell (x, y) if the * cell is empty. The shark's hunger is represented by the third parameter. * If the cell is already occupied, leave the cell as it is. You will need * this method to help convert run-length encodings to Oceans. * @param x is the x-coordinate of the cell to place a shark in. * @param y is the y-coordinate of the cell to place a shark in. * @param feeding is an integer that indicates the shark's hunger. You may * encode it any way you want; for instance, "feeding" may be the * last timestep the shark was fed, or the amount of time that has * passed since the shark was last fed, or the amount of time left * before the shark will starve. It's up to you, but be consistent. */

public void addShark(int x, int y, int feeding) { // Your solution here. }

/** * The following method is required for Part III.

Page 45: java book

*/

/** * sharkFeeding() returns an integer that indicates the hunger of the shark * in cell (x, y), using the same "feeding" representation as the parameter * to addShark() described above. If cell (x, y) does not contain a shark, * then its return value is undefined--that is, anything you want. * Normally, this method should not be called if cell (x, y) does not * contain a shark. You will need this method to help convert Oceans to * run-length encodings. * @param x is the x-coordinate of the cell whose contents are queried. * @param y is the y-coordinate of the cell whose contents are queried. */

public int sharkFeeding(int x, int y) { // Replace the following line with your solution. return 0; }

}

/* Ocean.java */

/** * The Ocean class defines an object that models an ocean full of sharks and * fish. Descriptions of the methods you must implement appear below. They * include a constructor of the form * * public Ocean(int i, int j, int starveTime); * * that creates an empty ocean having width i and height j, and the specified * shark starveTime. * * See the README file accompanying this project for additional details. */

public class Ocean {

/* You may renumber these constants if you wish, but don't rename them. */

Page 46: java book

public final static int EMPTY = 0; public final static int SHARK = 1; public final static int FISH = 2;

/** * Define any variables associated with an Ocean object here. These * variables MUST be private. */

/** * The following methods are required for Part I. */

/** * Ocean() is a constructor that creates an empty ocean having width i, * height j, and the specified shark starveTime. */

public Ocean(int i, int j, int starveTime) { // Your solution here. }

/** * width() returns the width of an Ocean object. * @return the width of the ocean. */

public int width() { // Replace the following line with your solution. return 1; }

/** * height() returns the height of an Ocean object. * @return the height of the ocean. */

public int height() { // Replace the following line with your solution. return 1; }

/** * starveTime() returns the shark starveTime of an Ocean object. * @return the shark starveTime. */

public int starveTime() { // Replace the following line with your solution. return 1; }

/**

Page 47: java book

* addFish() places a fish in cell (x, y) if the cell is empty. If the * cell is already occupied, leave the cell as it is. * @param x is the x-coordinate of the cell to place a fish in. * @param y is the y-coordinate of the cell to place a fish in. */

public void addFish(int x, int y) { // Your solution here. }

/** * addShark() (with two parameters) places a newborn shark in cell (x, y) if * the cell is empty. A "newborn" shark is equivalent to a shark that has * just eaten. If the cell is already occupied, leave the cell as it is. * @param x is the x-coordinate of the cell to place a shark in. * @param y is the y-coordinate of the cell to place a shark in. */

public void addShark(int x, int y) { // Your solution here. }

/** * cellContents() returns EMPTY if cell (x, y) is empty, FISH if it contains * a fish, and SHARK if it contains a shark. * @param x is the x-coordinate of the cell whose contents are queried. * @param y is the y-coordinate of the cell whose contents are queried. */

public int cellContents(int x, int y) { // Replace the following line with your solution. return EMPTY; }

/** * timeStep() performs a simulation timestep as described in README. * @return an ocean representing the elapse of one timestep. */

public Ocean timeStep() { // Replace the following line with your solution. return new Ocean(1, 1, 1); }

/** * The following method is required for Part II. */

/**

Page 48: java book

* addShark() (with three parameters) places a shark in cell (x, y) if the * cell is empty. The shark's hunger is represented by the third parameter. * If the cell is already occupied, leave the cell as it is. You will need * this method to help convert run-length encodings to Oceans. * @param x is the x-coordinate of the cell to place a shark in. * @param y is the y-coordinate of the cell to place a shark in. * @param feeding is an integer that indicates the shark's hunger. You may * encode it any way you want; for instance, "feeding" may be the * last timestep the shark was fed, or the amount of time that has * passed since the shark was last fed, or the amount of time left * before the shark will starve. It's up to you, but be consistent. */

public void addShark(int x, int y, int feeding) { // Your solution here. }

/** * The following method is required for Part III. */

/** * sharkFeeding() returns an integer that indicates the hunger of the shark * in cell (x, y), using the same "feeding" representation as the parameter * to addShark() described above. If cell (x, y) does not contain a shark, * then its return value is undefined--that is, anything you want. * Normally, this method should not be called if cell (x, y) does not * contain a shark. You will need this method to help convert Oceans to * run-length encodings. * @param x is the x-coordinate of the cell whose contents are queried. * @param y is the y-coordinate of the cell whose contents are queried. */

public int sharkFeeding(int x, int y) { // Replace the following line with your solution. return 0; }

}

Page 49: java book

/* RunLengthEncoding.java */

/** * The RunLengthEncoding class defines an object that run-length encodes an * Ocean object. Descriptions of the methods you must implement appear below. * They include constructors of the form * * public RunLengthEncoding(int i, int j, int starveTime); * public RunLengthEncoding(int i, int j, int starveTime, * int[] runTypes, int[] runLengths) { * public RunLengthEncoding(Ocean ocean) { * * that create a run-length encoding of an Ocean having width i and height j, * and the specified shark starveTime. The first constructor creates a * run-length encoding of an Ocean in which every cell is empty. The second * constructor creates a run-length encoding for which the runs are provided * as parameters. The third constructor converts an Ocean object into a * run-length encoding of that object. * * See the README file accompanying this project for additional details. */

public class RunLengthEncoding {

/** * Define any variables associated with a RunLengthEncoding object here. * These variables MUST be private. */

/**

Page 50: java book

* The following methods are required for Part II. */

/** * RunLengthEncoding() (with three parameters) is a constructor that creates * a run-length encoding of an empty ocean having width i and height j, * and the specified starveTime. * @param i is the width of the ocean. * @param j is the height of the ocean. * @param starveTime is the number of timesteps for shark starvation. */

public RunLengthEncoding(int i, int j, int starveTime) { // Your solution here. }

/** * RunLengthEncoding() (with five parameters) is a constructor that creates * a run-length encoding of an ocean having width i and height j, and the * specified starveTime. The runs of the run-length encoding are taken from * two input arrays. Run i has length runLengths[i] and species * runTypes[i]. * @param i is the width of the ocean. * @param j is the height of the ocean. * @param starveTime is the number of timesteps for shark starvation. * @param runTypes is an array that represents the species represented by * each run. Each element of runTypes is Ocean.EMPTY, Ocean.FISH, * or Ocean.SHARK. Any run of sharks is treated as a run of newborn * sharks (which are equivalent to sharks that have just eaten). * @param runLengths is an array that represents the length of each run. * The sum of all elements of the runLengths array should be i * j. */

public RunLengthEncoding(int i, int j, int starveTime, int[] runTypes, int[] runLengths) { // Your solution here. }

/** * restartRuns() and nextRun() are two methods that work together to return * all the runs in the run-length encoding, one by one. Each time * nextRun() is invoked, it returns a different run (represented as a * TypeAndSize object), until every run has been returned. The first time

Page 51: java book

* nextRun() is invoked, it returns the first run in the encoding, which * contains cell (0, 0). After every run has been returned, nextRun() * returns null, which lets the calling program know that there are no more * runs in the encoding. * * The restartRuns() method resets the enumeration, so that nextRun() will * once again enumerate all the runs as if nextRun() were being invoked for * the first time. * * (Note: Don't worry about what might happen if nextRun() is interleaved * with addFish() or addShark(); it won't happen.) */

/** * restartRuns() resets the enumeration as described above, so that * nextRun() will enumerate all the runs from the beginning. */

public void restartRuns() { // Your solution here. }

/** * nextRun() returns the next run in the enumeration, as described above. * If the runs have been exhausted, it returns null. The return value is * a TypeAndSize object, which is nothing more than a way to return two * integers at once. * @return the next run in the enumeration, represented by a TypeAndSize * object. */

public TypeAndSize nextRun() { // Replace the following line with your solution. return new TypeAndSize(Ocean.EMPTY, 1); }

/** * toOcean() converts a run-length encoding of an ocean into an Ocean * object. You will need to implement the three-parameter addShark method * in the Ocean class for this method's use. * @return the Ocean represented by a run-length encoding. */

public Ocean toOcean() { // Replace the following line with your solution. return new Ocean(1, 1);

Page 52: java book

}

/** * The following method is required for Part III. */

/** * RunLengthEncoding() (with one parameter) is a constructor that creates * a run-length encoding of an input Ocean. You will need to implement * the sharkFeeding method in the Ocean class for this constructor's use. * @param sea is the ocean to encode. */

public RunLengthEncoding(Ocean sea) { // Your solution here, but you should probably leave the following line // at the end. check(); }

/** * The following methods are required for Part IV. */

/** * addFish() places a fish in cell (x, y) if the cell is empty. If the * cell is already occupied, leave the cell as it is. The final run-length * encoding should be compressed as much as possible; there should not be * two consecutive runs of sharks with the same degree of hunger. * @param x is the x-coordinate of the cell to place a fish in. * @param y is the y-coordinate of the cell to place a fish in. */

public void addFish(int x, int y) { // Your solution here, but you should probably leave the following line // at the end. check(); }

/** * addShark() (with two parameters) places a newborn shark in cell (x, y) if * the cell is empty. A "newborn" shark is equivalent to a shark that has * just eaten. If the cell is already occupied, leave the cell as it is. * The final run-length encoding should be compressed as much as possible; * there should not be two consecutive runs of sharks with the same degree

Page 53: java book

* of hunger. * @param x is the x-coordinate of the cell to place a shark in. * @param y is the y-coordinate of the cell to place a shark in. */

public void addShark(int x, int y) { // Your solution here, but you should probably leave the following line // at the end. check(); }

/** * check() walks through the run-length encoding and prints an error message * if two consecutive runs have the same contents, or if the sum of all run * lengths does not equal the number of cells in the ocean. */

public void check() { }

}

/* SimText.java */

/* DO NOT CHANGE THIS FILE (except as noted). *//* YOUR SUBMISSION MUST WORK CORRECTLY WITH _OUR_ COPY OF THIS FILE. */

/* (You may wish to make temporary changes or insert println() statements *//* while testing your code. When you're finished testing and debugging, *//* though, make sure your code works with the original version of this file. */

import java.util.*;

/** * The SimText class is a program that runs and animates a simulation of * Sharks and Fish. * * The SimText program takes up to four parameters. The first two specify

Page 54: java book

* the width and height of the ocean. The third parameter specifies the value * of starveTime. For example, if you run * * java SimText 25 25 1 * * then SimText will animate a 25x25 ocean with a starveTime of 1. If you run * "java SimText" with no parameters, by default SimText will animate a 50x25 * ocean with a starveTime of 3. With some choices of parameters, the ocean * quickly dies out; with others, it teems forever. * * @author Jonathan Shewchuk */

public class SimText {

/** * Default parameters. (You may change these if you wish.) */

private static int i = 50; // Default ocean width private static int j = 25; // Default ocean height private static int starveTime = 3; // Default shark starvation time

/** * paint() prints an Ocean. */

public static void paint(Ocean sea) { if (sea != null) { int width = sea.width(); int height = sea.height();

/* Draw the ocean. */ for (int x = 0; x < width + 2; x++) { System.out.print("-"); } System.out.println(); for (int y = 0; y < height; y++) { System.out.print("|"); for (int x = 0; x < width; x++) { int contents = sea.cellContents(x, y); if (contents == Ocean.SHARK) { System.out.print('S'); } else if (contents == Ocean.FISH) { System.out.print('~'); } else { System.out.print(' '); } } System.out.println("|");

Page 55: java book

} for (int x = 0; x < width + 2; x++) { System.out.print("-"); } System.out.println(); } }

/** * main() reads the parameters and performs the simulation and animation. */

public static void main(String[] argv) throws InterruptedException { Ocean sea;

/** * Read the input parameters. */

if (argv.length > 0) { try { i = Integer.parseInt(argv[0]); } catch (NumberFormatException e) { System.out.println("First argument to SimText is not an number."); } }

if (argv.length > 1) { try { j = Integer.parseInt(argv[1]); } catch (NumberFormatException e) { System.out.println("Second argument to SimText is not an number."); } }

if (argv.length > 2) { try { starveTime = Integer.parseInt(argv[2]); } catch (NumberFormatException e) { System.out.println("Third argument to SimText is not an number."); } }

/** * Create the initial ocean. */

sea = new Ocean(i, j, starveTime);

/**

Page 56: java book

* Visit each cell (in a roundabout order); randomly place a fish, shark, * or nothing in each. */

Random random = new Random(0); // Create a "Random" object with seed 0 int x = 0; int y = 0; for (int xx = 0; xx < i; xx++) { x = (x + 78887) % i; // This will visit every x-coordinate once if ((x < 25) || (x >= i - 25)) { for (int yy = 0; yy < j; yy++) { y = (y + 78887) % j; // This will visit every y-coordinate once if ((y < 25) || (y >= j - 25)) { int r = random.nextInt(); // Between -2147483648 and 2147483647 if (r < 0) { // 50% of cells start with fish sea.addFish(x, y); } else if (r > 1500000000) { // ~15% of cells start with sharks sea.addShark(x, y); } } } } }

/** * Perform timesteps forever. */

while (true) { // Loop forever paint(sea); // For fun, you might wish to change the delay in the next line. Thread.sleep(1000); // Wait one second (1000 milliseconds) sea = sea.timeStep(); // Simulate a timestep } }

}

Page 57: java book

/* Simulation.java */

/* DO NOT CHANGE THIS FILE (except as noted). *//* YOUR SUBMISSION MUST WORK CORRECTLY WITH _OUR_ COPY OF THIS FILE. */

/* (You may wish to make temporary changes or insert println() statements *//* while testing your code. When you're finished testing and debugging, *//* though, make sure your code works with the original version of this file. */

import java.awt.*;import java.util.*;

/** * The Simulation class is a program that runs and animates a simulation of * Sharks and Fish. * * The Simulation program takes up to four parameters. The first two specify * the width and height of the ocean. The third parameter specifies the value * of starveTime. For example, if you run * * java SimText 25 25 1 * * then Simulation will animate a 25x25 ocean with a starveTime of 1. If you * run "java SimText" with no parameters, by default Simulation will animate * a 50x25 ocean with a starveTime of 3. With some choices of parameters, * the ocean quickly dies out; with others, it teems forever. * * @author Jonathan Shewchuk */

public class Simulation {

/** * The constant cellSize determines the size of each cell on the screen * during animation. (You may change this if you wish.) */

private static final int cellSize = 4;

/** * Default parameters. (You may change these if you wish.) */

private static int i = 50; // Default ocean width

Page 58: java book

private static int j = 25; // Default ocean height private static int starveTime = 3; // Default shark starvation time

private static void drawOcean(Graphics graphics, Ocean ocean) { if (ocean != null) { int width = ocean.width(); int height = ocean.height();

for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int contents = ocean.cellContents(x, y); if (contents == Ocean.SHARK) { graphics.setColor(Color.red); // Draw a red shark graphics.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); } else if (contents == Ocean.FISH) { graphics.setColor(Color.green); // Draw a green fish graphics.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); } else { graphics.clearRect(x * cellSize, y * cellSize, cellSize, cellSize); } } } } }

/** * main() reads the parameters and performs the simulation and animation. */

public static void main(String[] argv) throws InterruptedException { Ocean sea;

/** * Read the input parameters.

/* DList.java */

package list;

/** * A DList is a mutable doubly-linked list ADT. Its implementation is * circularly-linked and employs a sentinel (dummy) node at the head * of the list. * * DO NOT CHANGE ANY METHOD PROTOTYPES IN THIS FILE. */

public class DList {

Page 59: java book

/** * head references the sentinel node. * size is the number of items in the list. (The sentinel node does not * store an item.) * * DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS. */

protected DListNode head; protected int size;

/* DList invariants: * 1) head != null. * 2) For any DListNode x in a DList, x.next != null and x.prev != null. * 3) For any DListNode x in a DList, if x.next == y, then y.prev == x. * 4) For any DListNode x in a DList, if x.prev == y, then y.next == x. * 5) The "size" field is the number of DListNodes, excepting the sentinel, * that can be accessed from the sentinel by a sequence of "next" * references. */

/** * newNode() calls the DListNode constructor. Use this class to allocate * new DListNodes rather than calling the DListNode constructor directly. * That way, only this method need be overridden if a subclass of DList * wants to use a different kind of node. * @param item the item to store in the node. * @param prev the node previous to this node. * @param next the node following this node. */ public DListNode newNode(Object item, DListNode prev, DListNode next) { return new DListNode(item, prev, next); }

/** * DList() constructor for an empty DList. */ public DList() { // Your solution here. }

/** * isEmpty() returns true if this DList is empty, false otherwise. * @return true if this DList is empty, false otherwise. * Performance: runs in O(1) time. */ public boolean isEmpty() {

Page 60: java book

return size == 0; }

/** * length() returns the length of this DList. * @return the length of this DList. * Performance: runs in O(1) time. */ public int length() { return size; }

/** * insertFront() inserts an item at the front of this DList. * @param item is the item to be inserted. * Performance: runs in O(1) time. */ public void insertFront(Object item) { // Your solution here. }

/** * insertBack() inserts an item at the back of this DList. * @param item is the item to be inserted. * Performance: runs in O(1) time. */ public void insertBack(Object item) { // Your solution here. }

/** * front() returns the node at the front of this DList. If the DList is * empty, return null. * * Do NOT return the sentinel under any circumstances! * * @return the node at the front of this DList. * Performance: runs in O(1) time. */ public DListNode front() { // Your solution here. }

/** * back() returns the node at the back of this DList. If the DList is * empty, return null. * * Do NOT return the sentinel under any circumstances! * * @return the node at the back of this DList. * Performance: runs in O(1) time. */ public DListNode back() { // Your solution here. }

Page 61: java book

/** * next() returns the node following "node" in this DList. If "node" is * null, or "node" is the last node in this DList, return null. * * Do NOT return the sentinel under any circumstances! * * @param node the node whose successor is sought. * @return the node following "node". * Performance: runs in O(1) time. */ public DListNode next(DListNode node) { // Your solution here. }

/** * prev() returns the node prior to "node" in this DList. If "node" is * null, or "node" is the first node in this DList, return null. * * Do NOT return the sentinel under any circumstances! * * @param node the node whose predecessor is sought. * @return the node prior to "node". * Performance: runs in O(1) time. */ public DListNode prev(DListNode node) { // Your solution here. }

/** * insertAfter() inserts an item in this DList immediately following "node". * If "node" is null, do nothing. * @param item the item to be inserted. * @param node the node to insert the item after. * Performance: runs in O(1) time. */ public void insertAfter(Object item, DListNode node) { // Your solution here. }

/** * insertBefore() inserts an item in this DList immediately before "node". * If "node" is null, do nothing. * @param item the item to be inserted. * @param node the node to insert the item before. * Performance: runs in O(1) time. */ public void insertBefore(Object item, DListNode node) { // Your solution here. }

/**

Page 62: java book

* remove() removes "node" from this DList. If "node" is null, do nothing. * Performance: runs in O(1) time. */ public void remove(DListNode node) { // Your solution here. }

/** * toString() returns a String representation of this DList. * * DO NOT CHANGE THIS METHOD. * * @return a String representation of this DList. * Performance: runs in O(n) time, where n is the length of the list. */ public String toString() { String result = "[ "; DListNode current = head.next; while (current != head) { result = result + current.item + " "; current = current.next; } return result + "]"; }

public static void main(String[] args) { // You may put test code here. It will not be graded. // But if you don't test your code, it's not likely to pass our tests. }

}

/* DListNode.java */

package list;

Page 63: java book

/** * A DListNode is a node in a DList (doubly-linked list). */

public class DListNode {

/** * item references the item stored in the current node. * prev references the previous node in the DList. * next references the next node in the DList. * * DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS. */

public Object item; protected DListNode prev; protected DListNode next;

/** * DListNode() constructor. * @param i the item to store in the node. * @param p the node previous to this node. * @param n the node following this node. */ DListNode(Object i, DListNode p, DListNode n) { item = i; prev = p; next = n; }}

/* Set.java */

import list.*;

/** * A Set is a collection of Comparable elements stored in sorted order. * Duplicate elements are not permitted in a Set. **/public class Set { /* Fill in the data fields here. */

/** * Set invariants: * 1) The Set's elements must be precisely the elements of the List. * 2) The List must always contain Comparable elements, and those elements * must always be sorted in ascending order. * 3) No two elements in the List may be equals(). **/

/**

Page 64: java book

* Constructs an empty Set. * * Performance: runs in O(1) time. **/ public Set() { // Your solution here. }

/** * cardinality() returns the number of elements in this Set. * * Performance: runs in O(1) time. **/ public int cardinality() { // Replace the following line with your solution. return 0; }

/** * insert() inserts a Comparable element into this Set. * * Sets are maintained in sorted order. The ordering is specified by the * compareTo() method of the java.lang.Comparable interface. * * Performance: runs in O(this.cardinality()) time. **/ public void insert(Comparable c) { // Your solution here. }

/** * union() modifies this Set so that it contains all the elements it * started with, plus all the elements of s. The Set s is NOT modified. * Make sure that duplicate elements are not created. * * Performance: Must run in O(this.cardinality() + s.cardinality()) time. * * Your implementation should NOT copy elements of s or "this", though it * will copy references to the elements of s. Your implementation will * create new nodes for the elements of s that are added to "this", but you * should reuse the nodes that are alread part of "this". * * DO NOT MODIFY THE SET s. * DO NOT ATTEMPT TO COPY ELEMENTS; just copy references to them. **/ public void union(Set s) { // Your solution here. }

/**

Page 65: java book

* intersect() modifies this Set so that it contains the intersection of * its own elements and the elements of s. The Set s is NOT modified. * * Performance: Must run in O(this.cardinality() + s.cardinality()) time. * * Do not construct any new ListNodes during the execution of intersect. * Reuse the nodes of "this" that will be in the intersection result. * * DO NOT MODIFY THE SET s. * DO NOT CONSTRUCT ANY NEW NODES. * DO NOT ATTEMPT TO COPY ELEMENTS. **/ public void intersect(Set s) { // Your solution here. }

/** * toString() returns a String representation of this Set. The String must * have the following format: * { } for an empty Set. No spaces before "{" or after "}"; two spaces * between them. * { 1 2 3 } for a Set of three Integer elements. No spaces before * "{" or after "}"; two spaces before and after each element. * Elements are printed with their own toString method, whatever * that may be. The elements must appear in sorted order, from * lowest to highest according to the compareTo() method. * * WARNING: THE AUTOGRADER EXPECTS YOU TO PRINT SETS IN _EXACTLY_ THIS * FORMAT, RIGHT UP TO THE TWO SPACES BETWEEN ELEMENTS. ANY * DEVIATIONS WILL LOSE POINTS. **/ public String toString() { // Replace the following line with your solution. return ""; }

public static void main(String[] argv) { Set s = new Set(); s.insert(new Integer(3)); s.insert(new Integer(4)); s.insert(new Integer(3)); System.out.println("Set s = " + s);

Set s2 = new Set(); s2.insert(new Integer(4));

Page 66: java book

s2.insert(new Integer(5)); s2.insert(new Integer(5)); System.out.println("Set s2 = " + s2);

Set s3 = new Set(); s3.insert(new Integer(5)); s3.insert(new Integer(3)); s3.insert(new Integer(8)); System.out.println("Set s3 = " + s3);

s.union(s2); System.out.println("After s.union(s2), s = " + s);

s.intersect(s3); System.out.println("After s.intersect(s3), s = " + s);

System.out.println("s.cardinality() = " + s.cardinality()); // You may want to add more (ungraded) test code here. }}

/* DList.java */

package list;

/** * A DList is a mutable doubly-linked list ADT. Its implementation is * circularly-linked and employs a sentinel (dummy) node at the head of the * list. * * DO NOT CHANGE ANY METHOD PROTOTYPES IN THIS FILE. **/

public class DList extends List {

/** * (inherited) size is the number of items in the list. * head references the sentinel node. * Note that the sentinel node does not store an item, and is not included * in the count stored by the "size" field. * * DO NOT CHANGE THE FOLLOWING FIELD DECLARATION. **/

protected DListNode head;

/* DList invariants: * 1) head != null. * 2) For any DListNode x in a DList, x.next != null and x.prev != null. * 3) For any DListNode x in a DList, if x.next == y, then y.prev == x.

Page 67: java book

* 4) For any DListNode x in a DList, if x.prev == y, then y.next == x. * 5) The "size" field is the number of DListNodes, excepting the sentinel, * that can be accessed from the sentinel by a sequence of "next" * references. **/

/** * newNode() calls the DListNode constructor. Use this method to allocate * new DListNodes rather than calling the DListNode constructor directly. * That way, only this method need be overridden if a subclass of DList * wants to use a different kind of node. * * @param item the item to store in the node. * @param prev the node previous to this node. * @param next the node following this node. **/ protected DListNode newNode(Object item, DListNode prev, DListNode next) { return new DListNode(item, this, prev, next); }

/** * DList() constructs for an empty DList. **/ public DList() { // Your solution (from Homework 4) here. }

/** * insertFront() inserts an item at the front of this DList. * * @param item is the item to be inserted. * * Performance: runs in O(1) time. **/ public void insertFront(Object item) { // Your solution (from Homework 4) here. }

/** * insertBack() inserts an item at the back of this DList. * * @param item is the item to be inserted. * * Performance: runs in O(1) time. **/ public void insertBack(Object item) { // Your solution (from Homework 4) here. }

/**

Page 68: java book

* front() returns the node at the front of this DList. If the DList is * empty, return an "invalid" node--a node with the property that any * attempt to use it will cause an exception. (The sentinel is "invalid".) * * DO NOT CHANGE THIS METHOD. * * @return a ListNode at the front of this DList. * * Performance: runs in O(1) time. */ public ListNode front() { return head.next; }

/** * back() returns the node at the back of this DList. If the DList is * empty, return an "invalid" node--a node with the property that any * attempt to use it will cause an exception. (The sentinel is "invalid".) * * DO NOT CHANGE THIS METHOD. * * @return a ListNode at the back of this DList. * * Performance: runs in O(1) time. */ public ListNode back() { return head.prev; }

/** * toString() returns a String representation of this DList. * * DO NOT CHANGE THIS METHOD. * * @return a String representation of this DList. * * Performance: runs in O(n) time, where n is the length of the list. */ public String toString() { String result = "[ "; DListNode current = head.next; while (current != head) { result = result + current.item + " "; current = current.next; } return result + "]"; }

private static void testInvalidNode(ListNode p) { System.out.println("p.isValidNode() should be false: " + p.isValidNode()); try {

Page 69: java book

p.item(); System.out.println("p.item() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.item() should throw an exception, and did."); } try { p.setItem(new Integer(0)); System.out.println("p.setItem() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.setItem() should throw an exception, and did."); } try { p.next(); System.out.println("p.next() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.next() should throw an exception, and did."); } try { p.prev(); System.out.println("p.prev() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.prev() should throw an exception, and did."); } try { p.insertBefore(new Integer(1)); System.out.println("p.insertBefore() should throw an exception, but " + "didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.insertBefore() should throw an exception, and did." ); } try { p.insertAfter(new Integer(1)); System.out.println("p.insertAfter() should throw an exception, but " + "didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.insertAfter() should throw an exception, and did." ); } try { p.remove(); System.out.println("p.remove() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) {

Page 70: java book

System.out.println("p.remove() should throw an exception, and did."); } }

private static void testEmpty() { List l = new DList(); System.out.println("An empty list should be [ ]: " + l); System.out.println("l.isEmpty() should be true: " + l.isEmpty()); System.out.println("l.length() should be 0: " + l.length()); System.out.println("Finding front node p of l."); ListNode p = l.front(); testInvalidNode(p); System.out.println("Finding back node p of l."); p = l.back(); testInvalidNode(p); l.insertFront(new Integer(10)); System.out.println("l after insertFront(10) should be [ 10 ]: " + l); }

public static void main(String[] argv) { testEmpty(); List l = new DList(); l.insertFront(new Integer(3)); l.insertFront(new Integer(2)); l.insertFront(new Integer(1)); System.out.println("l is a list of 3 elements: " + l); try { ListNode n; int i = 1; for (n = l.front(); n.isValidNode(); n = n.next()) {

System.out.println("n.item() should be " + i + ": " + n.item()); n.setItem(new Integer(((Integer) n.item()).intValue() * 2));

System.out.println("n.item() should be " + 2 * i + ": " + n.item());

i++; } System.out.println("After doubling all elements of l: " + l); testInvalidNode(n);

i = 6; for (n = l.back(); n.isValidNode(); n = n.prev()) {

System.out.println("n.item() should be " + i + ": " + n.item());n.setItem(new Integer(((Integer) n.item()).intValue() * 2));System.out.println("n.item() should be " + 2 * i + ": " +

n.item());i = i - 2;

} System.out.println("After doubling all elements of l again: " + l); testInvalidNode(n);

n = l.front().next(); System.out.println("Removing middle element (8) of l: " + n.item()); n.remove();

Page 71: java book

System.out.println("l is now: " + l); testInvalidNode(n); n = l.back(); System.out.println("Removing end element (12) of l: " + n.item()); n.remove(); System.out.println("l is now: " + l); testInvalidNode(n);

n = l.front(); System.out.println("Removing first element (4) of l: " + n.item()); n.remove(); System.out.println("l is now: " + l); testInvalidNode(n); } catch (InvalidNodeException lbe) { System.err.println ("Caught InvalidNodeException that should not happen." ); System.err.println ("Aborting the testing code."); } }}

/* DListNode.java */

package list;

/** * A DListNode is a mutable node in a DList (doubly-linked list). **/

public class DListNode extends ListNode {

/** * (inherited) item references the item stored in the current node. * (inherited) myList references the List that contains this node. * prev references the previous node in the DList. * next references the next node in the DList. * * DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS. **/

protected DListNode prev; protected DListNode next;

/** * DListNode() constructor. * @param i the item to store in the node. * @param l the list this node is in. * @param p the node previous to this node. * @param n the node following this node. */ DListNode(Object i, DList l, DListNode p, DListNode n) { item = i; myList = l; prev = p;

Page 72: java book

next = n; }

/** * isValidNode returns true if this node is valid; false otherwise. * For convenience, an invalid node may be represented in one of two ways: * as a node that doesn't belong to a list (myList is null), or as the * sentinel node of its DList. * * @return true if this node is valid; false otherwise. * * Performance: runs in O(1) time. */ public boolean isValidNode() { return (myList != null) && (((DList) myList).head != this); }

/** * next() returns the node following this node. If this node is invalid, * throws an exception. * * @return the node following this node. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(1) time. */ public ListNode next() throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("next() called on invalid node"); } return next; }

/** * prev() returns the node preceding this node. If this node is invalid, * throws an exception. * * @param node the node whose predecessor is sought. * @return the node preceding this node. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(1) time. */ public ListNode prev() throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("prev() called on invalid node"); } return prev; }

/** * insertAfter() inserts an item immediately following this node. If this

Page 73: java book

* node is invalid, throws an exception. * * @param item the item to be inserted. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(1) time. */ public void insertAfter(Object item) throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("insertAfter() called on invalid node"); } // Your solution here. Will look something like your Homework 4 solution, // but changes are necessary. For instance, there is no need to check if // "this" is null. Remember that this node's "myList" fields tells you // what DList it's in. You should use myList.newNode() to create the // new node. }

/** * insertBefore() inserts an item immediately preceding this node. If this * node is invalid, throws an exception. * * @param item the item to be inserted. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(1) time. */ public void insertBefore(Object item) throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("insertBefore() called on invalid node"); } // Your solution here. Will look something like your Homework 4 solution, // but changes are necessary. For instance, there is no need to check if // "this" is null. Remember that this node's "myList" fields tells you // what DList it's in. You should use myList.newNode() to create the // new node. }

/** * remove() removes this node from its DList. If this node is invalid, * throws an exception. * * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(1) time.

Page 74: java book

*/ public void remove() throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("remove() called on invalid node"); } // Your solution here. Will look something like your Homework 4 solution, // but changes are necessary. For instance, there is no need to check if // "this" is null. Remember that this node's "myList" fields tells you // what DList it's in.

// Make this node an invalid node, so it cannot be used to corrupt myList. myList = null; // Set other references to null to improve garbage collection. next = null; prev = null; }

}

/* InvalidNodeException.java */

package list;

/** * Implements an Exception that signals an attempt to use an invalid ListNode. */

public class InvalidNodeException extends Exception { protected InvalidNodeException() { super(); }

protected InvalidNodeException(String s) { super(s); }}

/* List.java */

Page 75: java book

package list;

/** * A List is a mutable list ADT. No implementation is provided. * * DO NOT CHANGE THIS FILE. **/

public abstract class List {

/** * size is the number of items in the list. **/

protected int size;

/** * isEmpty() returns true if this List is empty, false otherwise. * * @return true if this List is empty, false otherwise. * * Performance: runs in O(1) time. **/ public boolean isEmpty() { return size == 0; }

/** * length() returns the length of this List. * * @return the length of this List. * * Performance: runs in O(1) time. **/ public int length() { return size; }

/** * insertFront() inserts an item at the front of this List. * * @param item is the item to be inserted. **/ public abstract void insertFront(Object item);

/** * insertBack() inserts an item at the back of this List. * * @param item is the item to be inserted. **/ public abstract void insertBack(Object item);

/** * front() returns the node at the front of this List. If the List is * empty, return an "invalid" node--a node with the property that any * attempt to use it will cause an exception.

Page 76: java book

* * @return a ListNode at the front of this List. */ public abstract ListNode front();

/** * back() returns the node at the back of this List. If the List is * empty, return an "invalid" node--a node with the property that any * attempt to use it will cause an exception. * * @return a ListNode at the back of this List. */ public abstract ListNode back();

/** * toString() returns a String representation of this List. * * @return a String representation of this List. */ public abstract String toString();

}

/* ListNode.java */

package list;

/** * A ListNode is a mutable node in a list. No implementation is provided. * * DO NOT CHANGE THIS FILE. **/

public abstract class ListNode {

/** * item references the item stored in the current node. * myList references the List that contains this node. * * DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS. */

protected Object item; protected List myList;

/** * isValidNode returns true if this node is valid; false otherwise. * By default, an invalid node is one that doesn't belong to a list (myList * is null), but subclasses can override this definition. *

Page 77: java book

* @return true if this node is valid; false otherwise. * * Performance: runs in O(1) time. */ public boolean isValidNode() { return myList != null; }

/** * item() returns this node's item. If this node is invalid, * throws an exception. * * @return the item stored in this node. * * Performance: runs in O(1) time. */ public Object item() throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException(); } return item; }

/** * setItem() sets this node's item to "item". If this node is invalid, * throws an exception. * * Performance: runs in O(1) time. */ public void setItem(Object item) throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException(); } this.item = item; }

/** * next() returns the node following this node. If this node is invalid, * throws an exception. * * @return the node following this node. * @exception InvalidNodeException if this node is not valid. */ public abstract ListNode next() throws InvalidNodeException;

/** * prev() returns the node preceding this node. If this node is invalid, * throws an exception. * * @param node the node whose predecessor is sought. * @return the node preceding this node. * @exception InvalidNodeException if this node is not valid. */ public abstract ListNode prev() throws InvalidNodeException;

Page 78: java book

/** * insertAfter() inserts an item immediately following this node. If this * node is invalid, throws an exception. * * @param item the item to be inserted. * @exception InvalidNodeException if this node is not valid. */ public abstract void insertAfter(Object item) throws InvalidNodeException;

/** * insertBefore() inserts an item immediately preceding this node. If this * node is invalid, throws an exception. * * @param item the item to be inserted. * @exception InvalidNodeException if this node is not valid. */ public abstract void insertBefore(Object item) throws InvalidNodeException;

/** * remove() removes this node from its List. If this node is invalid, * throws an exception. * * @exception InvalidNodeException if this node is not valid. */ public abstract void remove() throws InvalidNodeException;

}/* SList.java */

package list;

/** * A SList is a mutable singly-linked list ADT. Its implementation employs * a tail reference. * * DO NOT CHANGE THIS FILE. **/

public class SList extends List {

/** * (inherited) size is the number of items in the list. * head references the first node. * tail references the last node. **/

protected SListNode head; protected SListNode tail;

/* SList invariants:

Page 79: java book

* 1) Either head == null and tail == null, or tail.next == null and the * SListNode referenced by tail can be reached from the head by a * sequence of zero or more "next" references. This implies that the * list is not circularly linked. * 2) The "size" field is the number of SListNodes that can be accessed * from head (including head itself) by a sequence of "next" references. **/

/** * newNode() calls the SListNode constructor. Use this method to allocate * new SListNodes rather than calling the SListNode constructor directly. * That way, only this method need be overridden if a subclass of SList * wants to use a different kind of node. * * @param item the item to store in the node. * @param next the node following this node. **/ protected SListNode newNode(Object item, SListNode next) { return new SListNode(item, this, next); }

/** * SList() constructs for an empty SList. **/ public SList() { head = null; tail = null; size = 0; }

/** * insertFront() inserts an item at the front of this SList. * * @param item is the item to be inserted. * * Performance: runs in O(1) time. **/ public void insertFront(Object item) { head = newNode(item, head); if (size == 0) { tail = head; } size++; }

/** * insertBack() inserts an item at the back of this SList. * * @param item is the item to be inserted. *

Page 80: java book

* Performance: runs in O(1) time. **/ public void insertBack(Object item) { if (head == null) { head = newNode(item, null); tail = head; } else { tail.next = newNode(item, null); tail = tail.next; } size++; }

/** * front() returns the node at the front of this SList. If the SList is * empty, return an "invalid" node--a node with the property that any * attempt to use it will cause an exception. * * @return a ListNode at the front of this SList. * * Performance: runs in O(1) time. */ public ListNode front() { if (head == null) { // Create an invalid node. SListNode node = newNode(null, null); node.myList = null; return node; } else { return head; } }

/** * back() returns the node at the back of this SList. If the SList is * empty, return an "invalid" node--a node with the property that any * attempt to use it will cause an exception. * * @return a ListNode at the back of this SList. * * Performance: runs in O(1) time. */ public ListNode back() { if (tail == null) { // Create an invalid node. SListNode node = newNode(null, null); node.myList = null; return node; } else { return tail; } }

/** * toString() returns a String representation of this SList.

Page 81: java book

* * @return a String representation of this SList. * * Performance: runs in O(n) time, where n is the length of the list. */ public String toString() { String result = "[ "; SListNode current = head; while (current != null) { result = result + current.item + " "; current = current.next; } return result + "]"; }

private static void testInvalidNode(ListNode p) { System.out.println("p.isValidNode() should be false: " + p.isValidNode()); try { p.item(); System.out.println("p.item() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.item() should throw an exception, and did."); } try { p.setItem(new Integer(0)); System.out.println("p.setItem() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.setItem() should throw an exception, and did."); } try { p.next(); System.out.println("p.next() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.next() should throw an exception, and did."); } try { p.prev(); System.out.println("p.prev() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.prev() should throw an exception, and did."); } try { p.insertBefore(new Integer(1)); System.out.println("p.insertBefore() should throw an exception, but " + "didn't."); } catch (InvalidNodeException lbe) {

Page 82: java book

System.out.println("p.insertBefore() should throw an exception, and did." ); } try { p.insertAfter(new Integer(1)); System.out.println("p.insertAfter() should throw an exception, but " + "didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.insertAfter() should throw an exception, and did." ); } try { p.remove(); System.out.println("p.remove() should throw an exception, but didn't."); } catch (InvalidNodeException lbe) { System.out.println("p.remove() should throw an exception, and did."); } }

private static void testEmpty() { List l = new SList(); System.out.println("An empty list should be [ ]: " + l); System.out.println("l.isEmpty() should be true: " + l.isEmpty()); System.out.println("l.length() should be 0: " + l.length()); System.out.println("Finding front node p of l."); ListNode p = l.front(); testInvalidNode(p); System.out.println("Finding back node p of l."); p = l.back(); testInvalidNode(p); l.insertFront(new Integer(10)); System.out.println("l after insertFront(10) should be [ 10 ]: " + l); }

public static void main(String[] argv) { testEmpty(); List l = new SList(); l.insertFront(new Integer(3)); l.insertFront(new Integer(2)); l.insertFront(new Integer(1)); System.out.println("l is a list of 3 elements: " + l); try { ListNode n; int i = 1; for (n = l.front(); n.isValidNode(); n = n.next()) {

System.out.println("n.item() should be " + i + ": " + n.item()); n.setItem(new Integer(((Integer) n.item()).intValue() * 2));

System.out.println("n.item() should be " + 2 * i + ": " + n.item());

i++; }

Page 83: java book

System.out.println("After doubling all elements of l: " + l); testInvalidNode(n);

i = 6; for (n = l.back(); n.isValidNode(); n = n.prev()) {

System.out.println("n.item() should be " + i + ": " + n.item());n.setItem(new Integer(((Integer) n.item()).intValue() * 2));System.out.println("n.item() should be " + 2 * i + ": " +

n.item());i = i - 2;

} System.out.println("After doubling all elements of l again: " + l); testInvalidNode(n);

n = l.front().next(); System.out.println("Removing middle element (8) of l: " + n.item()); n.remove(); System.out.println("l is now: " + l); testInvalidNode(n); n = l.back(); System.out.println("Removing end element (12) of l: " + n.item()); n.remove(); System.out.println("l is now: " + l); testInvalidNode(n);

n = l.front(); System.out.println("Removing first element (4) of l: " + n.item()); n.remove(); System.out.println("l is now: " + l); testInvalidNode(n); } catch (InvalidNodeException lbe) { System.err.println ("Caught InvalidNodeException that should not happen." ); System.err.println ("Aborting the testing code."); } }}

/* SListNode.java */

package list;

/** * An SListNode is a mutable node in an SList (singly-linked list). **/

public class SListNode extends ListNode {

/** * (inherited) item references the item stored in the current node.

Page 84: java book

* (inherited) myList references the List that contains this node. * next references the next node in the SList. * * DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS. **/

protected SListNode next;

/** * SListNode() constructor. * @param i the item to store in the node. * @param l the list this node is in. * @param n the node following this node. */ SListNode(Object i, SList l, SListNode n) { item = i; myList = l; next = n; }

/** * next() returns the node following this node. If this node is invalid, * throws an exception. * * @return the node following this node. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(1) time. */ public ListNode next() throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("next() called on invalid node"); } if (next == null) { // Create an invalid node. SListNode node = ((SList) myList).newNode(null, null); node.myList = null; return node; } else { return next; } }

/** * prev() returns the node preceding this node. If this node is invalid, * throws an exception. * * @param node the node whose predecessor is sought. * @return the node preceding this node. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(this.size) time. */ public ListNode prev() throws InvalidNodeException { if (!isValidNode()) {

Page 85: java book

throw new InvalidNodeException("prev() called on invalid node"); } SListNode prev = ((SList) myList).head; if (prev == this) { // Create an invalid node. prev = ((SList) myList).newNode(null, null); prev.myList = null; } else { while (prev.next != this) { prev = prev.next; } } return prev; }

/** * insertAfter() inserts an item immediately following this node. If this * node is invalid, throws an exception. * * @param item the item to be inserted. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(1) time. */ public void insertAfter(Object item) throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("insertAfter() called on invalid node"); } SListNode newNode = ((SList) myList).newNode(item, next); if (next == null) { ((SList) myList).tail = newNode; } next = newNode; myList.size++; }

/** * insertBefore() inserts an item immediately preceding this node. If this * node is invalid, throws an exception. * * @param item the item to be inserted. * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(this.size) time. */ public void insertBefore(Object item) throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("insertBefore() called on invalid node"); } SListNode newNode = ((SList) myList).newNode(item, this); if (this == ((SList) myList).head) { ((SList) myList).head = newNode; } else {

Page 86: java book

SListNode prev = (SListNode) prev(); prev.next = newNode; } myList.size++; }

/** * remove() removes this node from its SList. If this node is invalid, * throws an exception. * * @exception InvalidNodeException if this node is not valid. * * Performance: runs in O(this.size) time. */ public void remove() throws InvalidNodeException { if (!isValidNode()) { throw new InvalidNodeException("remove() called on invalid node"); } if (this == ((SList) myList).head) { ((SList) myList).head = next; if (next == null) { ((SList) myList).tail = null; } } else { SListNode prev = (SListNode) prev(); prev.next = next; if (next == null) { ((SList) myList).tail = prev; } } myList.size--;

// Make this node an invalid node, so it cannot be used to corrupt myList. myList = null; // Set other reference to null to improve garbage collection. next = null; }

}

/* Homework6Test.java */

import dict.*;

/** * Initializes a hash table, then stocks it with random SimpleBoards. * @author Daniel C. Silverstein **/

Page 87: java book

public class Homework6Test { /** * Generates a random 8 x 8 SimpleBoard. **/ private static SimpleBoard randomBoard() { SimpleBoard board = new SimpleBoard(); for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) {

double fval = Math.random() * 12;int value = (int) fval;board.setElementAt(x, y, value);

} } return board; }

/** * Empties the given table, then inserts the given number of boards * into the table. * @param table is the hash table to be initialized. * @param numBoards is the number of random boards to place in the table. **/ public static void initTable(HashTableChained table, int numBoards) { table.makeEmpty(); for (int i = 0; i < numBoards; i++) { table.insertItem(randomBoard(), new Integer(i)); } }

public static void main(String[] args) { int numBoards;

if (args.length == 0) { numBoards = 100; } else { numBoards = Integer.parseInt(args[0]); } HashTableChained table = new HashTableChained(numBoards); initTable(table, numBoards);

// To test your hash function, add a method to your HashTableChained class // that counts the number of collisions. Call this method from here. }

}

/* SimpleBoard.java */

/**

Page 88: java book

* Simple class that implements an 8x8 game board with three possible values * for each cell: 0, 1 or 2. * * DO NOT CHANGE ANY PROTOTYPES IN THIS FILE. **/public class SimpleBoard { private final static int DIMENSION = 8; private int[][] grid;

/** * Invariants: * (1) grid.length == DIMENSION. * (2) for all 0 <= i < DIMENSION, grid[i].length == DIMENSION. * (3) for all 0 <= i, j < DIMENSION, grid[i][j] >= 0 and grid[i][j] <= 2. **/

/** * Construct a new board in which all cells are empty. */ public SimpleBoard() { grid = new int[DIMENSION][DIMENSION]; }

/** * Set the cell (x, y) in the board to the given value % 3. * @param value to which the element should be set (normally 0, 1, or 2). * @param x is the x-index. * @param y is the y-index. * @exception ArrayIndexOutOfBoundsException is thrown if an invalid index * is given. **/ public void setElementAt(int x, int y, int value) { grid[x][y] = value % 3; }

/** * Get the valued stored in cell (x, y). * @param x is the x-index. * @param y is the y-index. * @return the stored value (between 0 and 2). * @exception ArrayIndexOutOfBoundsException is thrown if an invalid index * is given. */ public int elementAt(int x, int y) { return grid[x][y]; }

/** * Returns true if two boards have identical values in each cell. * @param board is the second SimpleBoard. * @return true if the boards are equal, false otherwise. * @exception ClassCastException if board is not a SimpleBoard.

Page 89: java book

*/ public boolean equals(Object board) { // Replace the following line with your solution. return false; }

/** * Returns a hash code for this SimpleBoard. * @return a number between Integer.MIN_VALUE and Integer.MAX_VALUE. */ public int hashCode() { // Replace the following line with your solution. return 99; }

}

/* Dictionary.java */

package dict;

/** * An interface for (unordered) dictionary ADTs. * * DO NOT CHANGE THIS FILE. **/public interface Dictionary {

/** * Special element returned by the search and remove methods when * no item with the specified key is stored in the dictionary. **/ public static final Object NO_SUCH_KEY = new String("Dictionary.NO_SUCH_KEY");

/** * Returns the number of items stored in the dictionary, where each item * is counted according to its multiplicity. * @return number of items in the dictionary. **/ public int size();

/** * Tests if the dictionary is empty. * * @return true if the dictionary has no items, false otherwise. **/ public boolean isEmpty();

/** * Insert an item (a key and an associated element). Multiple items with * the same key can coexist in the dictionary.

Page 90: java book

* * @param key the key by which the item can be retrieved. * @param element an arbitrary object. **/ public void insertItem(Object key, Object element);

/** * Search for an item with the specified key. If such an item is found, * return its element; otherwise return the special element NO_SUCH_KEY. * If several items have the specified key, one is chosen arbitrarily and * returned. * * @param key the search key. * @return element an element associated with the key, or NO_SUCH_KEY if no * item is associated with the specified key. **/ public Object findElement(Object key); /** * Remove an item with the specified key. If such an item is found, return * its element and remove it from the table; otherwise else return the * special element NO_SUCH_KEY. If several items have the specified key, * one is chosen arbitrarily, removed, and returned. * * @param key the search key. * @return element an element associated with the key, or NO_SUCH_KEY if no * item is associated with the specified key. */ public Object remove(Object key);

/** * Remove all items from the dictionary. */ public void makeEmpty();

}

/* HashTableChained.java */

package dict;

/** * HashTableChained implements a Dictionary as a hash table with chaining. * All objects used as keys must have a valid hashCode() method, which is * used to determine which bucket of the hash table an item is stored in.

Page 91: java book

* Each object's hashCode() is presumed to return an int between * Integer.MIN_VLAUE and Integer.MAX_VALUE; the code herein hashes the hash * code to select a bucket within the table's range. * * DO NOT CHANGE ANY PROTOTYPES IN THIS FILE. **/public class HashTableChained implements Dictionary { /** * Place any data fields here. **/

/** * Construct a new hash table intended to hold roughly sizeEstimate items. * (The precise number of buckets is up to you, but we recommend you use * a prime number, and shoot for a load factor between 0.5 and 1.) **/ public HashTableChained(int sizeEstimate) { // Your solution here. }

/** * Construct a new hash table with a default size. **/ public HashTableChained() { // Your solution here. }

/** * Converts a hash code in the range Integer.MIN_VALUE...Integer.MAX_VALUE * to a value in the range 0...size of hash table - 1. * * This function should have package protection (so we can test it), and * should be used by insertItem, findElement, and remove. **/ int hashFunction(int code) { // Replace the following line with your solution. return 88; }

/** * Returns the number of items stored in the dictionary, where each item * is counted according to its multiplicity. * @return number of items in the dictionary. **/ public int size() { // Replace the following line with your solution. return 0; }

/** * Tests if the dictionary is empty.

Page 92: java book

* * @return true if the dictionary has no items, false otherwise. **/ public boolean isEmpty() { // Replace the following line with your solution. return true; }

/** * Insert an item (a key and an associated element). Multiple items with * the same key can coexist in the dictionary. * * @param key the key by which the item can be retrieved. * @param element an arbitrary object. **/ public void insertItem(Object key, Object element) { // Your solution here. }

/** * Search for an item with the specified key. If such an item is found, * return its element; otherwise return the special element NO_SUCH_KEY. * If several items have the specified key, one is chosen arbitrarily and * returned. * * @param key the search key. * @return element an element associated with the key, or NO_SUCH_KEY if no * item is associated with the specified key. **/ public Object findElement(Object key) { // Replace the following line with your solution. return null; }

/** * Remove an item with the specified key. If such an item is found, return * its element and remove it from the table; otherwise else return the * special element NO_SUCH_KEY. If several items have the specified key, * one is chosen arbitrarily, removed, and returned. * * @param key the search key. * @return element an element associated with the key, or NO_SUCH_KEY if no * item is associated with the specified key. */ public Object remove(Object key) { // Replace the following line with your solution. return null; }

Page 93: java book

/** * Remove all items from the dictionary. */ public void makeEmpty() { // Your solution here. }

}

player

/* MachinePlayer.java */

package player;

/** * An implementation of an automatic Network player. Keeps track of moves * made by both players. Can select a move for itself. */public class MachinePlayer extends Player {

Page 94: java book

// Creates a machine player with the given color. Color is either 0 (black) // or 1 (white).

public MachinePlayer(int color) { }

// Creates a machine player with the given color and search depth. Color is // either 0 (black) or 1 (white). public MachinePlayer(int color, int searchDepth) { }

// Returns a new move by this player. Internally records the move as a move // by this player. public Move chooseMove() { return new Move(); }

// If the Move m is legal, records the move as a move by the opponent and // returns true. If the move is illegal, returns false without modifying // the internal state of this player. This method allows your opponents to // inform you of their moves. public boolean opponentMove(Move m) { return false; }

// If the Move m is legal, records the move as a move by this player and // returns true. If the move is illegal, returns false without modifying // the internal state of this player. This method is used to help set up // "Network problems" for your player to solve. public boolean forceMove(Move m) { return false; }

}

/* Move.java */

package player;

Page 95: java book

/** * A public class for holding all the fields in a move. This class is a * container for data, not an ADT; hence, all fields are public. * * The moveKind field stores the type of move. The x-coordinates index the * horizontal direction (left to right) and the y-coordinates index the * vertical direction (top to bottom). x- and y-coordinates start at zero. * * DO NOT CHANGE THIS FILE. */public class Move {

public final static int QUIT = 0; public final static int ADD = 1; public final static int STEP = 2;

public int moveKind; // ADD, STEP, or QUIT. public int x1; // If moveKind == ADD, then x1, y1 are the new public int y1; // position in which a chip is being added; public int x2; // x2, y2 are unused. public int y2; // If moveKind == STEP, then x1, y1 are the new // position, and x2, y2 are the old position // of the chip. // If moveKind == QUIT, then x1, x2, y1, y2 are unused.

// Construct a step move. public Move(int xx1, int yy1, int xx2, int yy2) { moveKind = STEP; x1 = xx1; x2 = xx2; y1 = yy1; y2 = yy2; }

// Construct an add move. public Move(int x, int y) { moveKind = ADD; x1 = x; y1 = y; }

// Construct a quit move. public Move() { moveKind = QUIT; }

// toString() converts the move to a String. public String toString() { switch (moveKind) { case QUIT: return "[quit]";

Page 96: java book

case ADD: return "[add to " + x1 + "" + y1 + "]"; default: return "[step from " + x2 + "" + y2 + " to " + x1 + "" + y1 + "]"; } }

}

/* Player.java */

package player;

/** * A class that is extended by all Network players (human and machine). * * DO NOT CHANGE THIS FILE. */public abstract class Player { // This player's name as recognized by the game Network. public String myName;

// Returns a new move by this player. Internally records the move as a move // by this player. public abstract Move chooseMove();

// If the Move m is legal, records the move as a move by the opponent and // returns true. If the move is illegal, returns false without modifying // the internal state of this player. This method allows your opponents to // inform you of their moves. public abstract boolean opponentMove(Move m);

// If the Move m is legal, records the move as a move by this player and // returns true. If the move is illegal, returns false without modifying // the internal state of this player. This method is used to help set up // "Network problems" for your player to solve. public abstract boolean forceMove(Move m);

}

Page 97: java book

/* IntDictionary.java */

package dict;

/** * An IntDictionary is a mutable ordered dictionary ADT. Each item is an int * key; there are no additional objects associated with the key. * * DO NOT CHANGE THIS FILE. * * @author Jonathan Shewchuk */

public abstract class IntDictionary {

/** * size is the number of items in the dictionary. **/

protected int size;

/** * isEmpty() returns true if this IntDictionary is empty, false otherwise. * * @return true if this IntDictionary is empty, false otherwise. * * Performance: runs in O(1) time. **/ public boolean isEmpty() { return size == 0; }

/** * size() returns the size of this IntDictionary. * * @return the size of this IntDictionary. * * Performance: runs in O(1) time. **/ public int size() { return size; }

}

Page 98: java book

/* Tree234.java */

package dict;

/** * A Tree234 implements an ordered integer dictionary ADT using a 2-3-4 tree. * Only int keys are stored; no object is associated with each key. Duplicate * keys are not stored in the tree. * * @author Jonathan Shewchuk **/public class Tree234 extends IntDictionary {

/** * (inherited) size is the number of keys in the dictionary. * root is the root of the 2-3-4 tree. * * You may add fields if you wish, but don't change anything that * would prevent toString or findKey from working correctly. **/ Tree234Node root;

public Tree234() { root = null; size = 0; }

/** * toString() prints this Tree234 as a String. Each node is printed * in the form such as (for a 3-key node) * * (child1)key1(child2)key2(child3)key3(child4) * * where each child is a recursive call to toString, and null children * are printed as a space with no parentheses. Here's an example. * ((1)7(11 16)22(23)28(37 49))50((60)84(86 95 100)) * * DO NOT CHANGE THIS METHOD. * * @return a String representation of the 2-3-4 tree. **/ public String toString() { if (root == null) { return "";

Page 99: java book

} else { return root.toString(); } }

/** * findKey() prints true if "key" is in this 2-3-4 tree; false otherwise. * * @param key is the key sought. * @return true if "key" is in the tree; false otherwise. **/ public boolean findKey(int key) { Tree234Node node = root; while (node != null) { if (key < node.key1) { node = node.child1; } else if (key == node.key1) { return true; } else if ((node.keys == 1) || (key < node.key2)) { node = node.child2; } else if (key == node.key2) { return true; } else if ((node.keys == 2) || (key < node.key3)) { node = node.child3; } else if (key == node.key3) { return true; } else { node = node.child4; } } return false; }

/** * insertKey() inserts the key "key" into this 2-3-4 tree. If "key" is * already present, a duplicate copy is NOT inserted. * * @param key is the key sought. **/ public void insertKey(int key) { // Fill in your solution here. }

/** * testHelper() prints the String representation of this tree, then * compares it with the expected String, and prints an error message if * the two are not equal. * * @param correctString is what the tree should look like. **/ public void testHelper(String correctString) { String treeString = toString(); System.out.println(treeString); if (!treeString.equals(correctString)) {

Page 100: java book

System.out.println("ERROR: Should be " + correctString); } }

/** * main() is a bunch of test code. Feel free to add test code of your own; * this code won't be tested or graded. **/ public static void main(String[] args) { Tree234 t = new Tree234();

System.out.println("\nInserting 84."); t.insertKey(84); t.testHelper("84");

System.out.println("\nInserting 7."); t.insertKey(7); t.testHelper("7 84");

System.out.println("\nInserting 22."); t.insertKey(22); t.testHelper("7 22 84");

System.out.println("\nInserting 95."); t.insertKey(95); t.testHelper("(7)22(84 95)");

System.out.println("\nInserting 50."); t.insertKey(50); t.testHelper("(7)22(50 84 95)");

System.out.println("\nInserting 11."); t.insertKey(11); t.testHelper("(7 11)22(50 84 95)");

System.out.println("\nInserting 37."); t.insertKey(37); t.testHelper("(7 11)22(37 50)84(95)");

System.out.println("\nInserting 60."); t.insertKey(60); t.testHelper("(7 11)22(37 50 60)84(95)");

System.out.println("\nInserting 1."); t.insertKey(1); t.testHelper("(1 7 11)22(37 50 60)84(95)");

System.out.println("\nInserting 23."); t.insertKey(23); t.testHelper("(1 7 11)22(23 37)50(60)84(95)");

System.out.println("\nInserting 16."); t.insertKey(16); t.testHelper("((1)7(11 16)22(23 37))50((60)84(95))");

System.out.println("\nInserting 100.");

Page 101: java book

t.insertKey(100); t.testHelper("((1)7(11 16)22(23 37))50((60)84(95 100))");

System.out.println("\nInserting 28."); t.insertKey(28); t.testHelper("((1)7(11 16)22(23 28 37))50((60)84(95 100))");

System.out.println("\nInserting 86."); t.insertKey(86); t.testHelper("((1)7(11 16)22(23 28 37))50((60)84(86 95 100))");

System.out.println("\nInserting 49."); t.insertKey(49); t.testHelper("((1)7(11 16)22(23)28(37 49))50((60)84(86 95 100))");

System.out.println("\nInserting 81."); t.insertKey(81); t.testHelper("((1)7(11 16)22(23)28(37 49))50((60 81)84(86 95 100))");

System.out.println("\nInserting 51."); t.insertKey(51); t.testHelper("((1)7(11 16)22(23)28(37 49))50((51 60 81)84(86 95 100))");

System.out.println("\nInserting 99."); t.insertKey(99); t.testHelper("((1)7(11 16)22(23)28(37 49))50((51 60 81)84(86)95(99 100))");

System.out.println("\nInserting 75."); t.insertKey(75); t.testHelper("((1)7(11 16)22(23)28(37 49))50((51)60(75 81)84(86)95" + "(99 100))");

System.out.println("\nInserting 66."); t.insertKey(66); t.testHelper("((1)7(11 16)22(23)28(37 49))50((51)60(66 75 81))84((86)95" + "(99 100))");

System.out.println("\nInserting 4."); t.insertKey(4); t.testHelper("((1 4)7(11 16))22((23)28(37 49))50((51)60(66 75 81))84" + "((86)95(99 100))");

System.out.println("\nInserting 80."); t.insertKey(80); t.testHelper("(((1 4)7(11 16))22((23)28(37 49)))50(((51)60(66)75" + "(80 81))84((86)95(99 100)))"); }

}/* Tree234Node.java */

Page 102: java book

package dict;

/** * A Tree234Node is a node in a 2-3-4 tree (Tree234 class). * * DO NOT CHANGE ANYTHING IN THIS FILE. * You may add helper methods and additional constructors, though. **/class Tree234Node {

/** * keys is the number of keys in this node. Always 1, 2, or 3. * key1 through key3 are the keys of this node. If keys == 1, the value * of key2 doesn't matter. If keys < 3, the value of key3 doesn't matter. * parent is this node's parent; null if this is the root. * child1 through child4 are the children of this node. If this is a leaf * node, they must all be set to null. If this node has no third and/or * fourth child, child3 and/or child4 must be set to null. **/ int keys; int key1; int key2; int key3; Tree234Node parent; Tree234Node child1; Tree234Node child2; Tree234Node child3; Tree234Node child4;

Tree234Node(Tree234Node p, int key) { keys = 1; key1 = key; parent = p; child1 = null; child2 = null; child3 = null; child4 = null; }

/** * toString() recursively prints this Tree234Node and its descendants as * a String. Each node is printed in the form such as (for a 3-key node) * * (child1)key1(child2)key2(child3)key3(child4) * * where each child is a recursive call to toString, and null children * are printed as a space with no parentheses. Here's an example. * ((1)7(11 16)22(23)28(37 49))50((60)84(86 95 100)) * * DO NOT CHANGE THIS METHOD.

Page 103: java book

**/ public String toString() { String s = "";

if (child1 != null) { s = "(" + child1.toString() + ")"; } s = s + key1; if (child2 != null) { s = s + "(" + child2.toString() + ")"; } else if (keys > 1) { s = s + " "; } if (keys > 1) { s = s + key2; if (child3 != null) { s = s + "(" + child3.toString() + ")"; } else if (keys > 2) { s = s + " "; } } if (keys > 2) { s = s + key3; if (child4 != null) { s = s + "(" + child4.toString() + ")"; } } return s; }

}

/* Timer.java */

/** * Implements a simple stopwatch/timer class based on wall-clock time. **/

/** * RUNNING() == true <==> start() called with no corresponding * call to stop() * * All times are given in units of msec. **/public class Timer {

private boolean running; private long tStart;

Page 104: java book

private long tFinish; private long tAccum;

/** * Initializes Timer to 0 msec **/ public Timer() { reset(); }

/** * Starts the timer. Accumulates time across multiple calls to start. **/ public void start() { running = true; tStart = System.currentTimeMillis(); tFinish = tStart; }

/** * Stops the timer. returns the time elapsed since the last matching call * to start(), or zero if no such matching call was made. **/ public long stop() { tFinish = System.currentTimeMillis(); if (running) { running = false;

long diff = tFinish - tStart; tAccum += diff; return diff; } return 0; }

/** * if RUNNING() ==> returns the time since last call to start() * if !RUNNING() ==> returns total elapsed time **/ public long elapsed() { if (running) { return System.currentTimeMillis() - tStart; }

return tAccum; }

/** * Stops timing, if currently RUNNING(); resets * accumulated time to 0. */ public void reset() { running = false; tStart = 0; tFinish = 0;

Page 105: java book

tAccum = 0; }

}/* ListSorts.java */

import list.*;

public class ListSorts {

private final static int SORTSIZE = 1000;

/** * makeQueueOfQueues() makes a queue of queues, each containing one element * of q. Upon completion of this method, q is empty. * @param q is a LinkedQueue of objects. * @return a LinkedQueue containing LinkedQueue objects, each of which * contains one object from q. **/ public static LinkedQueue makeQueueOfQueues(LinkedQueue q) { // Replace the following line with your solution. return null; }

/** * mergeSortedQueues() merges two sorted queues into a third. On completion * of this method, q1 and q2 are empty, and their elements have been merged * into the returned queue. * @param q1 is LinkedQueue of Comparable objects, sorted from smallest * to largest. * @param q2 is LinkedQueue of Comparable objects, sorted from smallest * to largest. * @return a LinkedQueue containing all the Comparable objects from q1 * and q2 (and nothing else), sorted from smallest to largest. **/ public static LinkedQueue mergeSortedQueues(LinkedQueue q1, LinkedQueue q2) { // Replace the following line with your solution. return null; }

/** * circularShift performs a circular shift consituting shiftAmount dequeues * and enqueues. For example, if q is [ 3 9 6 2 ] and shiftAmount is 2, * q becomes [ 6 2 3 9 ]. If q is empty, it is not changed. * @param q is a LinkedQueue. * @param shiftAmount is an int representing the number of shifts to be

Page 106: java book

* performed. **/ public static void circularShift(LinkedQueue q, int shiftAmount) { // Your solution here. }

/** * partition() partitions qIn using the pivot element. On completion of * this method, qIn is empty, and its elements have been moved to qSmall, * qEquals, and qLarge, according to their relationship to the pivot. * @param qIn is a LinkedQueue of Comparable objects. * @param pivot is a Comparable element used for partitioning. * @param qSmall is a LinkedQueue, in which all elements less than pivot * will be enqueued. * @param qEquals is a LinkedQueue, in which all elements equal to the pivot * will be enqueued. * @param qLarge is a LinkedQueue, in which all elements greater than pivot * will be enqueued. **/ public static void partition(LinkedQueue qIn, Comparable pivot, LinkedQueue qSmall, LinkedQueue qEquals, LinkedQueue qLarge) { // Your solution here. }

/** * mergeSort() sorts q from smallest to largest using merge sort. * @param q is a LinkedQueue of Comparable objects. **/ public static void mergeSort(LinkedQueue q) { // Your solution here. }

/** * quickSort() sorts q from smallest to largest using quicksort. * @param q is a LinkedQueue of Comparable objects. **/ public static void quickSort(LinkedQueue q) { // Your solution here. }

/** * makeRandom() builds a LinkedQueue of the indicated size containing * Integer elements. The elements are randomly chosen between 0 and size. * @param size is the size of the resulting LinkedQueue. **/ public static LinkedQueue makeRandom(int size) { LinkedQueue q = new LinkedQueue(); for (int i = 0; i < size; i++) { q.enqueue(new Integer((int) (size * Math.random()))); }

Page 107: java book

return q; }

/** * printQueue() prints the queue q on the standard output. * @param q is a LinkedQueue. q's elements are printed using their toString * method. **/ public static void printQueue(LinkedQueue q) { System.out.print("[ "); try { for (int i = 0; i < q.size(); i++) {

System.out.print(q.front() + " ");q.enqueue(q.dequeue());

} } catch (QueueEmptyException uf) { System.err.println("Error: attempt to dequeue from empty queue."); } System.out.println("]"); }

/** * main() performs some tests on merge sort and quicksort. Feel free to add * more tests of your own to make sure your algorithms works on boundary * cases. Your test code will not be graded. **/ public static void main(String [] args) {

LinkedQueue q = makeRandom(10); printQueue(q); mergeSort(q); printQueue(q);

q = makeRandom(10); printQueue(q); quickSort(q); printQueue(q);

/* Remove these comments for Part III. Timer stopWatch = new Timer(); q = makeRandom(SORTSIZE); stopWatch.start(); mergeSort(q); stopWatch.stop(); System.out.println("Merge sort time, " + SORTSIZE + " Integers: " + stopWatch.elapsed() + " msec.");

stopWatch.reset(); q = makeRandom(SORTSIZE); stopWatch.start(); quickSort(q); stopWatch.stop(); System.out.println("Quick sort time, " + SORTSIZE + " Integers: " +

Page 108: java book

stopWatch.elapsed() + " msec."); */ }

}

/* LinkedQueue.java */

package list;

public class LinkedQueue implements Queue {

private SListNode head; private SListNode tail; private int size;

/** * LinkedQueue() constructs an empty queue. **/ public LinkedQueue() { size = 0; head = null; tail = null; }

/** * size() returns the size of this Queue. * @return the size of this Queue. * Performance: runs in O(1) time. **/ public int size() { return size; }

/** * isEmpty() returns true if this Queue is empty, false otherwise. * @return true if this Queue is empty, false otherwise. * Performance: runs in O(1) time. **/ public boolean isEmpty() { return size == 0; }

/** * enqueue() inserts an object at the end of the Queue. * @param element the element to be enqueued. **/ public void enqueue(Object element) { if (head == null) { head = new SListNode(element); tail = head; } else { tail.next = new SListNode(element);

Page 109: java book

tail = tail.next; } size++; }

/** * dequeue() removes and returns the object at the front of the Queue. * @return the element dequeued. * @throws a QueueEmptyException if the Queue is empty. **/ public Object dequeue() throws QueueEmptyException { if (head == null) { throw new QueueEmptyException(); } else { Object o = head.item; head = head.next; size--; if (size == 0) { tail = null; } return o; } }

/** * dequeue() returns the object at the front of the Queue. * @return the element at the front of the Queue. * @throws a QueueEmptyException if the Queue is empty. **/ public Object front() throws QueueEmptyException { if (head == null) { throw new QueueEmptyException(); } else { return head.item; } }

/** * append() appends the contents of q onto the end of this LinkedQueue. * On completion, q is empty. * @param q the LinkedQueue whose contents should be appended onto this * LinkedQueue. **/ public void append(LinkedQueue q) { if (head == null) { head = q.head; } else { tail.next = q.head; } if (q.head != null) { tail = q.tail; } size = size + q.size; q.head = null;

Page 110: java book

q.tail = null; q.size = 0; }

}

/* Queue.java */

package list;

public interface Queue {

/** * size() returns the size of this Queue. * @return the size of this Queue. * Performance: runs in O(1) time. **/ public int size();

/** * isEmpty() returns true if this Queue is empty, false otherwise. * @return true if this Queue is empty, false otherwise. * Performance: runs in O(1) time. **/ public boolean isEmpty();

/** * enqueue() inserts an object at the end of the Queue. * @param element the element to be enqueued. **/ public void enqueue(Object element);

/** * dequeue() removes and returns the object at the front of the Queue. * @return the element dequeued. * @throws a QueueEmptyException if the Queue is empty. **/ public Object dequeue() throws QueueEmptyException;

/** * dequeue() returns the object at the front of the Queue. * @return the element at the front of the Queue. * @throws a QueueEmptyException if the Queue is empty. **/ public Object front() throws QueueEmptyException;

}

Page 111: java book

/* QueueEmptyException.java */

package list;

public class QueueEmptyException extends Exception {

public QueueEmptyException() { super(); }

public QueueEmptyException(String s) { super(s); }

}

/* SListNode.java */

package list;

/** * SListNode is a class used internally by the SList class. An SList object

Page 112: java book

* is a singly-linked list, and an SListNode is a node of a singly-linked * list. Each SListNode has two references: one to an object, and one to * the next node in the list. * * @author Kathy Yelick and Jonathan Shewchuk */

class SListNode { Object item; SListNode next;

/** * SListNode() (with one parameter) constructs a list node referencing the * item "obj". */

SListNode(Object obj) { item = obj; next = null; }

/** * SListNode() (with two parameters) constructs a list node referencing the * item "obj", whose next list node is to be "next". */

SListNode(Object obj, SListNode next) { item = obj; this.next = next; }

}

/* Maze.java */

import java.util.*;import set.*;

/**

Page 113: java book

* The Maze class represents a maze in a rectangular grid. There is exactly * one path between any two points. **/

public class Maze {

// Horizontal and vertical dimensions of the maze. protected int horiz; protected int vert; // Horizontal and vertical interior walls; each is true if the wall exists. protected boolean[][] hWalls; protected boolean[][] vWalls;

// Object for generting random numbers. private static Random random;

// Constants used in depth-first search (which checks for cycles in the // maze). private static final int STARTHERE = 0; private static final int FROMLEFT = 1; private static final int FROMRIGHT = 2; private static final int FROMABOVE = 3; private static final int FROMBELOW = 4;

/** * Maze() creates a rectangular maze having "horizontalSize" cells in the * horizontal direction, and "verticalSize" cells in the vertical direction. * There is a path between any two cells of the maze. A disjoint set data * structure is used to ensure that there is only one path between any two * cells. **/ public Maze(int horizontalSize, int verticalSize) { int i, j;

horiz = horizontalSize; vert = verticalSize; if ((horiz < 1) || (vert < 1) || ((horiz == 1) && (vert == 1))) { return; // There are no interior walls }

// Create all of the horizontal interior walls. Initially, every // horizontal wall exists; they will be removed later by the maze // generation algorithm. if (vert > 1) { hWalls = new boolean[horiz][vert - 1]; for (j = 0; j < vert - 1; j++) { for (i = 0; i < horiz; i++) { hWalls[i][j] = true; }

Page 114: java book

} } // Create all of the vertical interior walls. if (horiz > 1) { vWalls = new boolean[horiz - 1][vert]; for (i = 0; i < horiz - 1; i++) { for (j = 0; j < vert; j++) { vWalls[i][j] = true; } } }

/** * Fill in the rest of this method. You should go through all the walls of * the maze in random order, and remove any wall whose removal will not * create a cycle. Use the implementation of disjoint sets provided in the * set package to avoid creating any cycles. * * Note the method randInt() further below, which generates a random * integer. randInt() generates different numbers every time the program * is run, so that you can make lots of different mazes. **/

}

/** * toString() returns a string representation of the maze. **/ public String toString() { int i, j; String s = "";

// Print the top exterior wall. for (i = 0; i < horiz; i++) { s = s + "**"; } s = s + "*\n*";

// Print the maze interior. for (j = 0; j < vert; j++) { // Print a row of cells and vertical walls. for (i = 0; i < horiz - 1; i++) { if (vWalls[i][j]) { s = s + " *"; } else { s = s + " "; } } s = s + " *\n*";

Page 115: java book

if (j < vert - 1) { // Print a row of horizontal walls and wall corners. for (i = 0; i < horiz; i++) { if (hWalls[i][j]) { s = s + "**"; } else { s = s + " *"; } } s = s + "\n*"; } }

// Print the bottom exterior wall. (Note that the first asterisk has // already been printed.) for (i = 0; i < horiz; i++) { s = s + "**"; } return s + "\n"; }

/** * horizontalWall() determines whether the horizontal wall on the bottom * edge of cell (x, y) exists. If the coordinates (x, y) do not correspond * to an interior wall, true is returned. **/ public boolean horizontalWall(int x, int y) { if ((x < 0) || (y < 0) || (x > horiz - 1) || (y > vert - 2)) { return true; } return hWalls[x][y]; }

/** * verticalWall() determines whether the vertical wall on the right edge of * cell (x, y) exists. If the coordinates (x, y) do not correspond to an * interior wall, true is returned. **/ public boolean verticalWall(int x, int y) { if ((x < 0) || (y < 0) || (x > horiz - 2) || (y > vert - 1)) { return true; } return vWalls[x][y]; }

/** * randInt() returns a random integer from 0 to choices - 1. **/ private static int randInt(int choices) { if (random == null) { // Only executed first time randInt() is called

Page 116: java book

random = new Random(); // Create a "Random" object with random seed } int r = random.nextInt() % choices; // From 1 - choices to choices - 1 if (r < 0) { r = -r; // From 0 to choices - 1 } return r; }

/** * diagnose() checks the maze and prints a warning if not every cell can be * reached from the upper left corner cell, or if there is a cycle reachable * from the upper left cell. * * DO NOT CHANGE THIS METHOD. Your code is expected to work with our copy * of this method. **/ protected void diagnose() { if ((horiz < 1) || (vert < 1) || ((horiz == 1) && (vert == 1))) { return; // There are no interior walls }

boolean mazeFine = true;

// Create an array that indicates whether each cell has been visited during // a depth-first traversal. boolean[][] cellVisited = new boolean[horiz][vert]; // Do a depth-first traversal. if (depthFirstSearch(0, 0, STARTHERE, cellVisited)) { System.out.println("Your maze has a cycle."); mazeFine = false; }

// Check to be sure that every cell of the maze was visited. outerLoop: for (int j = 0; j < vert; j++) { for (int i = 0; i < horiz; i++) { if (!cellVisited[i][j]) { System.out.println("Not every cell in your maze is reachable from " + "every other cell."); mazeFine = false; break outerLoop; } } }

if (mazeFine) { System.out.println("What a fine maze you've created!");

Page 117: java book

} }

/** * depthFirstSearch() does a depth-first traversal of the maze, marking each * visited cell. Returns true if a cycle is found. * * DO NOT CHANGE THIS METHOD. Your code is expected to work with our copy * of this method. */ protected boolean depthFirstSearch(int x, int y, int fromWhere, boolean[][] cellVisited) { boolean cycleDetected = false; cellVisited[x][y] = true;

// Visit the cell to the right? if ((fromWhere != FROMRIGHT) && !verticalWall(x, y)) { if (cellVisited[x + 1][y]) { cycleDetected = true; } else { cycleDetected = depthFirstSearch(x + 1, y, FROMLEFT, cellVisited) || cycleDetected; } }

// Visit the cell below? if ((fromWhere != FROMBELOW) && !horizontalWall(x, y)) { if (cellVisited[x][y + 1]) { cycleDetected = true; } else { cycleDetected = depthFirstSearch(x, y + 1, FROMABOVE, cellVisited) || cycleDetected; } }

// Visit the cell to the left? if ((fromWhere != FROMLEFT) && !verticalWall(x - 1, y)) { if (cellVisited[x - 1][y]) { cycleDetected = true; } else { cycleDetected = depthFirstSearch(x - 1, y, FROMRIGHT, cellVisited) || cycleDetected; } }

// Visit the cell above? if ((fromWhere != FROMABOVE) && !horizontalWall(x, y - 1)) { if (cellVisited[x][y - 1]) { cycleDetected = true; } else { cycleDetected = depthFirstSearch(x, y - 1, FROMBELOW, cellVisited) ||

Page 118: java book

cycleDetected; } }

return cycleDetected; }

/** * main() creates a maze of dimensions specified on the command line, prints * the maze, and runs the diagnostic method to see if the maze is good. */ public static void main(String[] args) { int x = 39; int y = 15;

/** * Read the input parameters. */

if (args.length > 0) { try { x = Integer.parseInt(args[0]); } catch (NumberFormatException e) { System.out.println("First argument to Simulation is not an number."); } }

if (args.length > 1) { try { y = Integer.parseInt(args[1]); } catch (NumberFormatException e) { System.out.println("Second argument to Simulation is not an number."); } }

Maze maze = new Maze(x, y); System.out.print(maze); maze.diagnose(); }

}

Page 119: java book

/* DisjointSets.java */

package set;

/** * A disjoint sets ADT. Performs union-by-rank and path compression. * Implemented using arrays. There is no error checking whatsoever. * By adding your own error-checking, you might save yourself a lot of time * finding bugs in your application code for Project 3 and Homework 9. * Without error-checking, expect bad things to happen if you try to unite * two elements that are not roots of their respective sets, or are not * distinct. * * Elements are represented by ints, numbered from zero. * * @author Mark Allen Weiss **/

public class DisjointSets {

private int[] array;

/** * Construct a disjoint sets object. * * @param numElements the initial number of elements--also the initial * number of disjoint sets, since every element is initially in its own set. **/ public DisjointSets(int numElements) { array = new int [numElements]; for (int i = 0; i < array.length; i++) { array[i] = -1; } }

/** * union() unites two disjoint sets into a single set. A union-by-rank * heuristic is used to choose the new root. This method will corrupt * the data structure if root1 and root2 are not roots of their respective * sets, or if they're identical. * * @param root1 the root of the first set. * @param root2 the root of the other set. **/ public void union(int root1, int root2) {

Page 120: java book

if (array[root2] < array[root1]) { array[root1] = root2; // root2 is taller; make root2 new root } else { if (array[root1] == array[root2]) { array[root1]--; // Both trees same height; new one is taller } array[root2] = root1; // root1 equal or taller; make root1 new root } }

/** * find() finds the (int) name of the set containing a given element. * Performs path compression along the way. * * @param x the element sought. * @return the set containing x. **/ public int find(int x) { if (array[x] < 0) { return x; // x is the root of the tree; return it } else { // Find out who the root is; compress path by making the root x's parent. array[x] = find(array[x]); return array[x]; // Return the root } }

/** * main() is test code. All the find()s on the same output line should be * identical. **/ public static void main(String[] args) { int NumElements = 128; int NumInSameSet = 16;

DisjointSets s = new DisjointSets(NumElements); int set1, set2;

for (int k = 1; k < NumInSameSet; k *= 2) { for (int j = 0; j + k < NumElements; j += 2 * k) { set1 = s.find(j); set2 = s.find(j + k); s.union(set1, set2); } }

for (int i = 0; i < NumElements; i++) { System.out.print(s.find(i) + "*"); if (i % NumInSameSet == NumInSameSet - 1) { System.out.println();

Page 121: java book

} } System.out.println(); }}/* Sorts.java */

package sort;

public class Sorts {

/** * Place any class (static) variables you would like to have here. **/

/** * countingSort() sorts an array of int keys according to the * values of _one_ of the base-16 digits of each key. "whichDigit" * indicates which digit is the sort key. A zero means sort on the least * significant (ones) digit; a one means sort on the second least * significant (sixteens) digit; and so on. * @param key is an array of ints. Assume no key is negative. * @param whichDigit is a number in 0...7 specifying which base-16 digit * is the sort key. * @return an array of type int, having the same length as "keys" * and containing the same keys sorted according to the chosen digit. * Note: This is a _newly_ created array. **/ public static int[] countingSort(int[] keys, int whichDigit) { // Replace the following line with your solution. return null; }

/** * countingSort() sorts an array of int keys (using all 32 bits * of each key to determine the ordering). * @param key is an array of ints. Assume no key is negative. * @return an array of type int, having the same length as "keys" * and containing the same keys in sorted order. * Note: This is a _newly_ created array. **/ public static int[] radixSort(int[] keys) { // Replace the following line with your solution. return null; }

/** * yell() prints an array of int keys. Each key is printed in hexadecimal * (base 16). * @param key is an array of ints. **/ public static void yell(int[] keys) {

Page 122: java book

System.out.print("keys are [ "); for (int i = 0; i < keys.length; i++) { System.out.print(Integer.toString(keys[i], 16) + " "); } System.out.println("]"); }

/** * main() creates and sorts a sample array. * We recommend you add more tests of your own. * Your test code will not be graded. **/ public static void main(String[] args) { int[] keys = { Integer.parseInt("60013879", 16), Integer.parseInt("11111119", 16), Integer.parseInt("2c735010", 16), Integer.parseInt("2c732010", 16), Integer.parseInt("7fffffff", 16), Integer.parseInt("4001387c", 16), Integer.parseInt("10111119", 16), Integer.parseInt("529a7385", 16), Integer.parseInt("1e635010", 16), Integer.parseInt("28905879", 16), Integer.parseInt("00011119", 16), Integer.parseInt("00000000", 16), Integer.parseInt("7c725010", 16), Integer.parseInt("1e630010", 16), Integer.parseInt("111111e5", 16), Integer.parseInt("61feed0c", 16), Integer.parseInt("3bba7387", 16), Integer.parseInt("52953fdb", 16), Integer.parseInt("40013879", 16) };

yell(keys); keys = radixSort(keys); yell(keys); }

}

/* Neighbors.java */

/* DO NOT CHANGE THIS FILE. */

Page 123: java book

/* YOUR SUBMISSION MUST WORK CORRECTLY WITH _OUR_ COPY OF THIS FILE. */

package graph;

/** * The Neighbors class is provided solely as a way to allow the method * WUGraph.getNeighbors() to return two arrays at once. Do NOT use this class * for any other purpose. * * Since this class is NOT an abstract data type, but is merely a collection of * data, all fields are public. */

public class Neighbors { public Object[] neighborList; public int[] weightList;}

/* VertexPair.java */

package graph;

/** * The VertexPair represents a pair of objects that act as vertices in a * WUGraph (weighted, undirected graph). The purpose of a VertexPair is to * act as a key in Java's built-in Hashtable class. The hashCode() and * equals() functions, which are called by Java's hash tables, are designed * so that the order of the two objects is immaterial; (u, v) is the same as * (v, u). */

class VertexPair { protected Object object1; protected Object object2;

protected VertexPair(Object o1, Object o2) { object1 = o1; object2 = o2;

Page 124: java book

}

/** * hashCode() returns a hashCode equal to the sum of the hashCodes of each * of the two objects of the pair, so that the order of the objects will * not affect the hashCode. Self-edges are treated differently: we don't * add an object's hashCode to itself, since the result would always be even. * We add one to the hashCode so that a self-edge will not collide with the * object itself if vertices and edges are stored in the same hash table. */ public int hashCode() { if (object1 == object2) { return object1.hashCode() + 1; } else { return object1.hashCode() + object2.hashCode(); } }

/** * equals() returns true if this VertexPair represents the same unordered * pair of objects as the parameter "o". The order of the pair does not * affect the equality test, so (u, v) is found to be equal to (v, u). */ public boolean equals(Object o) { if (o instanceof VertexPair) { return ((object1 == ((VertexPair) o).object1) && (object2 == ((VertexPair) o).object2)) || ((object1 == ((VertexPair) o).object2) && (object2 == ((VertexPair) o).object1)); } else { return false; } }}

Page 125: java book

/* WUGraph.java */

package graph;

import java.util.Hashtable;

/** * The WUGraph class represents a weighted, undirected graph. Self-edges are * permitted. */

public class WUGraph {

/** * WUGraph() constructs a graph having no vertices or edges. */ public WUGraph();

/** * vertexCount() returns the number of vertices in the graph. */ public int vertexCount();

/** * edgeCount() returns the number of edges in the graph. */ public int edgeCount();

/** * getVertices() returns an array containing all the objects that serve * as vertices of the graph. The array's length is exactly equal to the * number of vertices. If the graph has no vertices, null is returned. * * (NOTE: Do not return any internal data structure you use to represent * vertices! Return only the same objects that were provided by the * calling application in calls to addVertex().) */ public Object[] getVertices();

/** * addVertex() adds a vertex (with no incident edges) to the graph. The * vertex's "name" is the object provided as the parameter "vertex". * If this object is already a vertex of the graph, the graph is unchanged. */ public void addVertex(Object vertex);

/** * removeVertex() removes a vertex from the graph. All edges incident on the

Page 126: java book

* deleted vertex are removed as well. If the parameter "vertex" does not * represent a vertex of the graph, the graph is unchanged. */ public void removeVertex(Object vertex);

/** * isVertex() returns true if the parameter "vertex" represents a vertex of * the graph. */ public boolean isVertex(Object vertex);

/** * degree() returns the degree of a vertex. Self-edges add only one to the * degree of a vertex. If the parameter "vertex" doesn't represent a vertex * of the graph, zero is returned. */ public int degree(Object vertex);

/** * getNeighbors() returns a new Neighbors object referencing two arrays. The * Neighbors.neighborList array contains each object that is connected to the * input object by an edge. The Neighbors.weightList array contains the * weights of the corresponding edges. The length of both arrays is equal to * the number of edges incident on the input vertex. If the vertex has * degree zero, or if the parameter "vertex" does not represent a vertex of * the graph, null is returned (instead of a Neighbors object). * * The returned Neighbors object, and the two arrays, are both newly created. * No previously existing Neighbors object or array is changed. * * (NOTE: In the neighborList array, do not return any internal data * structure you use to represent vertices! Return only the same objects * that were provided by the calling application in calls to addVertex().) */ public Neighbors getNeighbors(Object vertex);

/** * addEdge() adds an edge (u, v) to the graph. If either of the parameters * u and v does not represent a vertex of the graph, the graph is unchanged. * The edge is assigned a weight of "weight". If the edge is already * contained in the graph, the weight is updated to reflect the new value.

Page 127: java book

* Self-edges (where u == v) are allowed. */ public void addEdge(Object u, Object v, int weight);

/** * removeEdge() removes an edge (u, v) from the graph. If either of the * parameters u and v does not represent a vertex of the graph, the graph * is unchanged. If (u, v) is not an edge of the graph, the graph is * unchanged. */ public void removeEdge(Object u, Object v);

/** * isEdge() returns true if (u, v) is an edge of the graph. Returns false * if (u, v) is not an edge (including the case where either of the * parameters u and v does not represent a vertex of the graph). */ public boolean isEdge(Object u, Object v);

/** * weight() returns the weight of (u, v). Returns zero if (u, v) is not * an edge (including the case where either of the parameters u and v does * not represent a vertex of the graph). * * (NOTE: A well-behaved application should try to avoid calling this * method for an edge that is not in the graph, and should certainly not * treat the result as if it actually represents an edge with weight zero. * However, some sort of default response is necessary for missing edges, * so we return zero. An exception would be more appropriate, but * also more annoying.) */ public int weight(Object u, Object v);

}

/* DisjointSets.java */

package set;

/**

Page 128: java book

* A disjoint sets ADT. Performs union-by-rank and path compression. * Implemented using arrays. There is no error checking whatsoever. * By adding your own error-checking, you might save yourself a lot of time * finding bugs in your application code for Project 3 and Homework 9. * Without error-checking, expect bad things to happen if you try to unite * two elements that are not roots of their respective sets, or are not * distinct. * * Elements are represented by ints, numbered from zero. * * @author Mark Allen Weiss **/

public class DisjointSets {

private int[] array;

/** * Construct a disjoint sets object. * * @param numElements the initial number of elements--also the initial * number of disjoint sets, since every element is initially in its own set. **/ public DisjointSets(int numElements) { array = new int [numElements]; for (int i = 0; i < array.length; i++) { array[i] = -1; } }

/** * union() unites two disjoint sets into a single set. A union-by-rank * heuristic is used to choose the new root. This method will corrupt * the data structure if root1 and root2 are not roots of their respective * sets, or if they're identical. * * @param root1 the root of the first set. * @param root2 the root of the other set. **/ public void union(int root1, int root2) { if (array[root2] < array[root1]) { array[root1] = root2; // root2 is taller; make root2 new root } else { if (array[root1] == array[root2]) { array[root1]--; // Both trees same height; new one is taller } array[root2] = root1; // root1 equal or taller; make root1 new root

Page 129: java book

} }

/** * find() finds the (int) name of the set containing a given element. * Performs path compression along the way. * * @param x the element sought. * @return the set containing x. **/ public int find(int x) { if (array[x] < 0) { return x; // x is the root of the tree; return it } else { // Find out who the root is; compress path by making the root x's parent. array[x] = find(array[x]); return array[x]; // Return the root } }

/** * main() is test code. All the find()s on the same output line should be * identical. **/ public static void main(String[] args) { int NumElements = 128; int NumInSameSet = 16;

DisjointSets s = new DisjointSets(NumElements); int set1, set2;

for (int k = 1; k < NumInSameSet; k *= 2) { for (int j = 0; j + k < NumElements; j += 2 * k) { set1 = s.find(j); set2 = s.find(j + k); s.union(set1, set2); } }

for (int i = 0; i < NumElements; i++) { System.out.print(s.find(i) + "*"); if (i % NumInSameSet == NumInSameSet - 1) { System.out.println(); } } System.out.println(); }}

Page 130: java book

/* Kruskal.java */

import java.util.Hashtable;import graph.*;import set.*;

/** * The Kruskal class contains the method minSpanTree(), which implements * Kruskal's algorithm for computing a minimum spanning tree of a graph. */

public class Kruskal {

/** * minSpanTree() returns a WUGraph that represents the minimum spanning tree * of the WUGraph g. The original WUGraph g is NOT changed. */ public static WUGraph minSpanTree(WUGraph g);

}

/* KruskalTest.java */

/** * The KruskalTest class tests the Kruskal class. */

import graph.*;import java.util.*;

public class KruskalTest {

private static final int VERTICES = 10; private static final int MAXINT = 100;

private static boolean tree = true; private static boolean minTree = true;

public static void addRandomEdges(WUGraph g, Object[] vertArray) { int i, j;

System.out.println("Adding random edges to graph.");

Page 131: java book

Random random = new Random(3); // Create a "Random" object with seed 0

for (i = 0; i < vertArray.length; i++) { for (j = i; j < vertArray.length; j++) { int r = random.nextInt() % MAXINT; // Between -99 and 99 if (r >= 0) { g.addEdge(vertArray[i], vertArray[j], r); } } } }

public static void DFS(WUGraph t, DFSVertex current, DFSVertex prev, int[] maxOnPath, int maxEdge) { Neighbors neigh; int i;

current.visited = true; maxOnPath[current.number] = maxEdge; neigh = t.getNeighbors(current); if (neigh != null) { for (i = 0; i < neigh.neighborList.length; i++) { DFSVertex next = (DFSVertex) neigh.neighborList[i]; if (next.visited) { if ((next != current) && (next != prev)) { tree = false; return; } } else if (neigh.weightList[i] > maxEdge) { DFS(t, next, current, maxOnPath, neigh.weightList[i]); } else { DFS(t, next, current, maxOnPath, maxEdge); } if (!tree) { return; } } } }

public static void DFSTest(WUGraph g, WUGraph t, DFSVertex[] vertArray) { int[][] maxOnPath; Neighbors neigh; int i, j;

System.out.println("Testing the tree.");

maxOnPath = new int[VERTICES][VERTICES]; for (i = 0; i < VERTICES; i++) { for (j = 0; j < VERTICES; j++) { vertArray[j].visited = false; } DFS(t, vertArray[i], null, maxOnPath[i], -MAXINT);

Page 132: java book

for (j = 0; j < VERTICES; j++) { if (!vertArray[j].visited) { tree = false; } } if (!tree) { return; } }

// for (i = 0; i < vertArray.length; i++) {// for (j = 0; j < vertArray.length; j++) {// System.out.print(" " + maxOnPath[i][j]);// }// System.out.println();// }

for (i = 0; i < VERTICES; i++) { neigh = g.getNeighbors(vertArray[i]); if (neigh != null) { for (j = 0; j < neigh.neighborList.length; j++) { int v = ((DFSVertex) neigh.neighborList[j]).number; if (neigh.weightList[j] < maxOnPath[i][v]) { minTree = false; } } } } }

public static void main(String[] args) { int i, j; int score; WUGraph g, t; DFSVertex[] vertArray;

System.out.println("Running minimum spanning tree test."); System.out.println("Creating empty graph."); g = new WUGraph();

System.out.println("Adding " + VERTICES + " vertices."); vertArray = new DFSVertex[VERTICES]; for (i = 0; i < VERTICES; i++) { vertArray[i] = new DFSVertex(); vertArray[i].number = i; g.addVertex(vertArray[i]); }

addRandomEdges(g, vertArray);

// for (i = 0; i < vertArray.length; i++) {// for (j = 0; j < vertArray.length; j++) {// System.out.print(" " + g.weight(vertArray[i], vertArray[j]));// }// System.out.println();// }

Page 133: java book

System.out.println("Finding the minimum spanning tree."); t = Kruskal.minSpanTree(g);

// for (i = 0; i < vertArray.length; i++) {// for (j = 0; j < vertArray.length; j++) {// System.out.print(" " + t.weight(vertArray[i], vertArray[j]));// }// System.out.println();// }

DFSTest(g, t, vertArray);

if (tree) { System.out.println("One point for creating a tree."); if (minTree) { System.out.println("Two points for creating a minimum spanning tree."); score = 3; } else { System.out.println("Not a minimum spanning tree."); score = 1; } } else { System.out.println("Not a tree."); score = 0; }

System.out.println("Your Kruskal test score is " + score + " out of 3."); System.out.println(" (Be sure also to run WUGTest.java.)"); }}

class DFSVertex { boolean visited; int number;}

/* WUGTest.java */

/** * The WUGTest class tests the WUGraph class. */

import graph.*;

public class WUGTest {

Page 134: java book

private static int vertexTest(Object[] vertArray) { int result; int countDeduction = 0; int getDeduction = 0; int isVDeduction = 0; WUGraph g; Object[] wuVertArray;

System.out.println("Running vertex test."); System.out.println("Creating empty graph."); g = new WUGraph(); result = g.vertexCount(); if (result != 0) { System.out.println("vertexCount() on empty graph returns " + result + " but should return 0."); countDeduction = 1; } result = g.edgeCount(); if (result != 0) { System.out.println("edgeCount() on empty graph returns " + result + " but should return 0."); countDeduction = 1; } if (g.getVertices() != null) { System.out.println("getVertices() on empty graph should return null" + " but doesn't."); getDeduction = 1; } if (g.isVertex(vertArray[0])) { System.out.println("isVertex() on vertex 0 should return false" + " but returns true."); isVDeduction = 1; }

System.out.println("Adding vertex 0."); g.addVertex(vertArray[0]); result = g.vertexCount(); if (result != 1) { System.out.println("vertexCount() returns " + result + " but should return 1."); countDeduction = 1; } if (!g.isVertex(vertArray[0])) { System.out.println("isVertex() on vertex 0 should return true" + " but returns false."); isVDeduction = 1; } if (g.isVertex(vertArray[1])) { System.out.println("isVertex() on vertex 1 should return false" + " but returns true."); isVDeduction = 1; } wuVertArray = g.getVertices(); if (wuVertArray == null) {

Page 135: java book

System.out.println("getVertices() returns null but shouldn't."); getDeduction = 1; } else if (wuVertArray.length != 1) { System.out.println("getVertices() returns array of length " + wuVertArray.length + "; should have length 1."); getDeduction = 1; } else if (wuVertArray[0] != vertArray[0]) { System.out.println("getVertices() returns array containing" + " the wrong object."); getDeduction = 1; }

System.out.println("Adding vertex 1."); g.addVertex(vertArray[1]); result = g.vertexCount(); if (result != 2) { System.out.println("vertexCount() returns " + result + " but should return 2."); countDeduction = 1; } if (!g.isVertex(vertArray[1])) { System.out.println("isVertex() on vertex 1 should return true" + " but returns false."); isVDeduction = 1; }

System.out.println("Adding vertex 0."); g.addVertex(vertArray[0]); result = g.vertexCount(); if (result != 2) { System.out.println("vertexCount() returns " + result + " but should return 2."); countDeduction = 1; } if (!g.isVertex(vertArray[0])) { System.out.println("isVertex() on vertex 0 should return true " + " but returns false."); isVDeduction = 1; } wuVertArray = g.getVertices(); if (wuVertArray == null) { System.out.println("getVertices() returns null but shouldn't."); getDeduction = 1; } else if (wuVertArray.length != 2) { System.out.println("getVertices() returns array of length " + wuVertArray.length + "; should have length 2."); getDeduction = 1; } else if (((wuVertArray[0] != vertArray[0]) || (wuVertArray[1] != vertArray[1])) && ((wuVertArray[0] != vertArray[1]) || (wuVertArray[1] != vertArray[0]))) { System.out.println("getVertices() returns array containing" + " wrong objects."); getDeduction = 1; }

Page 136: java book

System.out.println("Adding vertex 2."); g.addVertex(vertArray[2]); System.out.println("Adding vertex 3."); g.addVertex(vertArray[3]); System.out.println("Adding vertex 4."); g.addVertex(vertArray[4]); result = g.vertexCount(); if (result != 5) { System.out.println("vertexCount() returns " + result + " but should return 5."); countDeduction = 1; } wuVertArray = g.getVertices(); if (wuVertArray == null) { System.out.println("getVertices() returns null but shouldn't."); getDeduction = 1; } else if (wuVertArray.length != 5) { System.out.println("getVertices() returns array of length " + wuVertArray.length + "; should have length 5."); getDeduction = 1; }

System.out.println("Removing vertex 0."); g.removeVertex(vertArray[0]); System.out.println("Removing vertex 3."); g.removeVertex(vertArray[3]); result = g.vertexCount(); if (result != 3) { System.out.println("vertexCount() returns " + result + " but should return 3."); countDeduction = 1; } System.out.println("Removing vertex 3."); g.removeVertex(vertArray[3]); result = g.vertexCount(); if (result != 3) { System.out.println("vertexCount() returns " + result + " but should return 3."); countDeduction = 1; } result = g.edgeCount(); if (result != 0) { System.out.println("edgeCount() on empty graph returns " + result + " but should return 0."); countDeduction = 1; } if (g.isVertex(vertArray[0])) { System.out.println("isVertex() on vertex 0 should return false" + " but returns true."); isVDeduction = 1; } if (g.isVertex(vertArray[3])) { System.out.println("isVertex() on vertex 3 should return false" + " but returns true.");

Page 137: java book

isVDeduction = 1; } if (!g.isVertex(vertArray[4])) { System.out.println("isVertex() on vertex 4 should return true" + " but returns false."); isVDeduction = 1; } wuVertArray = g.getVertices(); if (wuVertArray == null) { System.out.println("getVertices() returns null but shouldn't."); getDeduction = 1; } else if (wuVertArray.length != 3) { System.out.println("getVertices() returns array of length " + wuVertArray.length + "; should have length 3."); getDeduction = 1; } else if (((wuVertArray[0] != vertArray[1]) && (wuVertArray[0] != vertArray[2]) && (wuVertArray[0] != vertArray[4])) || ((wuVertArray[1] != vertArray[1]) && (wuVertArray[1] != vertArray[2]) && (wuVertArray[1] != vertArray[4])) || ((wuVertArray[2] != vertArray[1]) && (wuVertArray[2] != vertArray[2]) && (wuVertArray[2] != vertArray[4]))) { System.out.println("getVertices() returns array containing " + "wrong objects."); getDeduction = 1; } else if ((wuVertArray[0] == wuVertArray[1]) || (wuVertArray[1] == wuVertArray[2]) || (wuVertArray[2] == wuVertArray[0])) { System.out.println("getVertices() returns array containing " + "duplicate objects."); getDeduction = 1; }

System.out.println(); return countDeduction + 2 * getDeduction + isVDeduction; }

private static int edgeTest(Object[] vertArray) { int result; int countDeduction = 0; int degreeDeduction = 0; int getDeduction = 0; int isDeduction = 0; int weightDeduction = 0; int remEDeduction = 0; int remVDeduction = 0; WUGraph g; Neighbors neigh;

System.out.println("Running edge test."); System.out.println("Creating empty graph."); g = new WUGraph(); System.out.println("Adding vertex 0."); g.addVertex(vertArray[0]);

Page 138: java book

System.out.println("Adding vertex 1."); g.addVertex(vertArray[1]); System.out.println("Adding vertex 2."); g.addVertex(vertArray[2]); System.out.println("Adding vertex 3."); g.addVertex(vertArray[3]); System.out.println("Adding vertex 4."); g.addVertex(vertArray[4]); System.out.println("Adding vertex 5."); g.addVertex(vertArray[5]); System.out.println("Adding vertex 6."); g.addVertex(vertArray[6]); System.out.println("Adding vertex 7."); g.addVertex(vertArray[7]); System.out.println("Adding vertex 8."); g.addVertex(vertArray[8]); System.out.println("Adding vertex 9."); g.addVertex(vertArray[9]);

result = g.degree(vertArray[3]); if (result != 0) { System.out.println("degree(vertex 3) returns " + result + " but should return 0."); degreeDeduction = 1; } if (g.getNeighbors(vertArray[3]) != null) { System.out.println("getNeighbors(vertex 3) should return null " + " but doesn't."); getDeduction = 1; } if (g.isEdge(vertArray[3], vertArray[7])) { System.out.println("isEdge(vertex 3, vertex 7) should return false " + " but returns true."); isDeduction = 1; } result = g.weight(vertArray[3], vertArray[7]); if (result != 0) { System.out.println("weight(vertex 3, vertex 7) returns " + result + " but should return 0."); weightDeduction = 1; } if (g.isEdge(vertArray[3], vertArray[3])) { System.out.println("isEdge(vertex 3, vertex 3) should return false " + " but returns true."); isDeduction = 1; } result = g.weight(vertArray[3], vertArray[3]); if (result != 0) { System.out.println("weight(vertex 3, vertex 3) returns " + result + " but should return 0."); weightDeduction = 1; }

Page 139: java book

System.out.println("Adding edge (3, 7) with weight 4."); g.addEdge(vertArray[3], vertArray[7], 4); result = g.vertexCount(); if (result != 10) { System.out.println("vertexCount() returns " + result + " but should return 10."); countDeduction = 1; } result = g.edgeCount(); if (result != 1) { System.out.println("edgeCount() returns " + result + " but should return 1."); countDeduction = 1; } if (!g.isEdge(vertArray[3], vertArray[7])) { System.out.println("isEdge(vertex 3, vertex 7) should return true " + " but returns false."); isDeduction = 1; } result = g.weight(vertArray[3], vertArray[7]); if (result != 4) { System.out.println("weight(vertex 3, vertex 7) returns " + result + " but should return 4."); weightDeduction = 1; } if (!g.isEdge(vertArray[7], vertArray[3])) { System.out.println("isEdge(vertex 7, vertex 3) should return true " + " but returns false."); isDeduction = 1; } result = g.weight(vertArray[7], vertArray[3]); if (result != 4) { System.out.println("weight(vertex 7, vertex 3) returns " + result + " but should return 4."); weightDeduction = 1; } result = g.degree(vertArray[3]); if (result != 1) { System.out.println("degree(vertex 3) returns " + result + " but should return 1."); degreeDeduction = 1; } result = g.degree(vertArray[7]); if (result != 1) { System.out.println("degree(vertex 7) returns " + result + " but should return 1."); degreeDeduction = 1; } result = g.degree(vertArray[0]); if (result != 0) { System.out.println("degree(vertex 0) returns " + result + " but should return 0."); degreeDeduction = 1;

Page 140: java book

}

System.out.println("Adding edge (3, 3) with weight 7."); g.addEdge(vertArray[3], vertArray[3], 7); result = g.edgeCount(); if (result != 2) { System.out.println("edgeCount() returns " + result + " but should return 2."); countDeduction = 1; } if (!g.isEdge(vertArray[3], vertArray[3])) { System.out.println("isEdge(vertex 3, vertex 3) should return true " + " but returns false."); isDeduction = 1; } result = g.weight(vertArray[3], vertArray[3]); if (result != 7) { System.out.println("weight(vertex 3, vertex 3) returns " + result + " but should return 7."); weightDeduction = 1; } result = g.degree(vertArray[3]); if (result != 2) { System.out.println("degree(vertex 3) returns " + result + " but should return 2."); degreeDeduction = 1; } result = g.degree(vertArray[7]); if (result != 1) { System.out.println("degree(vertex 7) returns " + result + " but should return 1."); degreeDeduction = 1; }

System.out.println("Adding edge (7, 3) with weight 9."); g.addEdge(vertArray[7], vertArray[3], 9); result = g.edgeCount(); if (result != 2) { System.out.println("edgeCount() returns " + result + " but should return 2."); countDeduction = 1; } if (!g.isEdge(vertArray[3], vertArray[7])) { System.out.println("isEdge(vertex 3, vertex 7) should return true " + " but returns false."); isDeduction = 1; } result = g.weight(vertArray[3], vertArray[7]); if (result != 9) { System.out.println("weight(vertex 3, vertex 7) returns " + result + " but should return 9."); weightDeduction = 1; }

Page 141: java book

if (!g.isEdge(vertArray[7], vertArray[3])) { System.out.println("isEdge(vertex 7, vertex 3) should return true " + " but returns false."); isDeduction = 1; } result = g.weight(vertArray[7], vertArray[3]); if (result != 9) { System.out.println("weight(vertex 7, vertex 3) returns " + result + " but should return 9."); weightDeduction = 1; } result = g.degree(vertArray[3]); if (result != 2) { System.out.println("degree(vertex 3) returns " + result + " but should return 2."); degreeDeduction = 1; } result = g.degree(vertArray[7]); if (result != 1) { System.out.println("degree(vertex 7) returns " + result + " but should return 1."); degreeDeduction = 1; } neigh = g.getNeighbors(vertArray[3]); if (neigh == null) { System.out.println("getNeighbors(vertex 3) improperly returns null."); getDeduction = 1; } else if (neigh.neighborList == null) { System.out.println("getNeighbors(vertex 3) improperly returns null" + " neighborList."); getDeduction = 1; } else if (neigh.weightList == null) { System.out.println("getNeighbors(vertex 3) improperly returns null" + " weightList."); getDeduction = 1; } else if (neigh.neighborList.length != 2) { System.out.println("getNeighbors(vertex 3) returns neighborList of" + " length " + neigh.neighborList.length + "; should have length 2."); getDeduction = 1; } else if (neigh.weightList.length != 2) { System.out.println("getNeighbors(vertex 3) returns weightList of" + " length " + neigh.weightList.length + "; should have length 2."); getDeduction = 1; } else if (((neigh.neighborList[0] != vertArray[3]) || (neigh.neighborList[1] != vertArray[7])) && ((neigh.neighborList[0] != vertArray[7]) || (neigh.neighborList[1] != vertArray[3]))) {

Page 142: java book

System.out.println("getNeighbors(vertex 3) returns array containing" + " wrong objects."); getDeduction = 1; } else if (((neigh.weightList[0] != 7) || (neigh.weightList[1] != 9)) && ((neigh.weightList[0] != 9) || (neigh.weightList[1] != 7))) { System.out.println("getNeighbors(vertex 3) returns array containing" + " wrong weights."); getDeduction = 1; }

System.out.println("Adding edge (9, 0) with weight -2."); g.addEdge(vertArray[9], vertArray[0], -2); System.out.println("Adding edge (9, 3) with weight 2."); g.addEdge(vertArray[9], vertArray[3], 2); System.out.println("Adding edge (1, 6) with weight 8."); g.addEdge(vertArray[1], vertArray[6], 8); System.out.println("Adding edge (9, 7) with weight 5."); g.addEdge(vertArray[9], vertArray[7], 5); System.out.println("Adding edge (3, 1) with weight 1."); g.addEdge(vertArray[3], vertArray[1], 1); System.out.println("Adding edge (1, 1) with weight 3."); g.addEdge(vertArray[1], vertArray[1], 3); result = g.edgeCount(); if (result != 8) { System.out.println("edgeCount() returns " + result + " but should return 8."); countDeduction = 1; } if (!g.isEdge(vertArray[1], vertArray[3])) { System.out.println("isEdge(vertex 1, vertex 3) should return true " + " but returns false."); isDeduction = 1; } result = g.weight(vertArray[1], vertArray[3]); if (result != 1) { System.out.println("weight(vertex 1, vertex 3) returns " + result + " but should return 1."); weightDeduction = 1; } if (!g.isEdge(vertArray[1], vertArray[1])) { System.out.println("isEdge(vertex 1, vertex 1) should return true " + " but returns false."); isDeduction = 1; } result = g.weight(vertArray[1], vertArray[1]); if (result != 3) { System.out.println("weight(vertex 1, vertex 1) returns " + result + " but should return 3."); weightDeduction = 1;

Page 143: java book

} result = g.degree(vertArray[3]); if (result != 4) { System.out.println("degree(vertex 3) returns " + result + " but should return 4."); degreeDeduction = 1; } result = g.degree(vertArray[1]); if (result != 3) { System.out.println("degree(vertex 1) returns " + result + " but should return 3."); degreeDeduction = 1; }

System.out.println("Removing edge (1, 6)."); g.removeEdge(vertArray[1], vertArray[6]); result = g.edgeCount(); if (result != 7) { System.out.println("edgeCount() returns " + result + " but should return 7."); remEDeduction = 1; } if (g.isEdge(vertArray[1], vertArray[6])) { System.out.println("isEdge(vertex 1, vertex 6) should return false " + " but returns true."); remEDeduction = 1; } if (g.isEdge(vertArray[6], vertArray[1])) { System.out.println("isEdge(vertex 6, vertex 1) should return false " + " but returns true."); remEDeduction = 1; } result = g.degree(vertArray[6]); if (result != 0) { System.out.println("degree(vertex 6) returns " + result + " but should return 0."); remEDeduction = 1; } result = g.degree(vertArray[1]); if (result != 2) { System.out.println("degree(vertex 1) returns " + result + " but should return 2."); remEDeduction = 1; }

System.out.println("Removing vertex 3."); g.removeVertex(vertArray[3]); result = g.vertexCount(); if (result != 9) { System.out.println("vertexCount() returns " + result + " but should return 9."); remVDeduction = 1; } result = g.edgeCount(); if (result != 3) {

Page 144: java book

System.out.println("edgeCount() returns " + result + " but should return 3."); remVDeduction = 1; } if (g.isVertex(vertArray[3])) { System.out.println("isVertex() on vertex 3 should return false" + " but returns true."); remVDeduction = 1; } result = g.degree(vertArray[3]); if (result != 0) { System.out.println("degree(vertex 3) returns " + result + " but should return 0."); remVDeduction = 1; } if (g.isEdge(vertArray[3], vertArray[3])) { System.out.println("isEdge(vertex 3, vertex 3) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[3], vertArray[7])) { System.out.println("isEdge(vertex 3, vertex 7) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[7], vertArray[3])) { System.out.println("isEdge(vertex 7, vertex 3) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[3], vertArray[9])) { System.out.println("isEdge(vertex 3, vertex 9) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[9], vertArray[3])) { System.out.println("isEdge(vertex 9, vertex 3) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[3], vertArray[1])) { System.out.println("isEdge(vertex 3, vertex 1) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[1], vertArray[3])) { System.out.println("isEdge(vertex 1, vertex 3) should return false " + " but returns true."); remVDeduction = 1; }

Page 145: java book

result = g.degree(vertArray[1]); if (result != 1) { System.out.println("degree(vertex 1) returns " + result + " but should return 1."); remVDeduction = 1; } result = g.degree(vertArray[7]); if (result != 1) { System.out.println("degree(vertex 7) returns " + result + " but should return 1."); remVDeduction = 1; } result = g.degree(vertArray[9]); if (result != 2) { System.out.println("degree(vertex 9) returns " + result + " but should return 2."); remVDeduction = 1; } neigh = g.getNeighbors(vertArray[7]); if (neigh == null) { System.out.println("getNeighbors(vertex 7) improperly returns null."); getDeduction = 1; } else if (neigh.neighborList == null) { System.out.println("getNeighbors(vertex 7) improperly returns null" + " neighborList."); getDeduction = 1; } else if (neigh.weightList == null) { System.out.println("getNeighbors(vertex 7) improperly returns null" + " weightList."); getDeduction = 1; } else if (neigh.neighborList.length != 1) { System.out.println("getNeighbors(vertex 7) returns neighborList of" + " length " + neigh.neighborList.length + "; should have length 1."); getDeduction = 1; } else if (neigh.weightList.length != 1) { System.out.println("getNeighbors(vertex 7) returns weightList of" + " length " + neigh.weightList.length + "; should have length 1."); getDeduction = 1; } else if (neigh.neighborList[0] != vertArray[9]) { System.out.println("getNeighbors(vertex 7) returns array containing" + " wrong object."); getDeduction = 1; } else if (neigh.weightList[0] != 5) { System.out.println("getNeighbors(vertex 7) returns array containing" + " wrong weight."); getDeduction = 1; }

Page 146: java book

System.out.println("Removing edge (1, 1)."); g.removeEdge(vertArray[1], vertArray[1]); result = g.edgeCount(); if (result != 2) { System.out.println("edgeCount() returns " + result + " but should return 2."); remVDeduction = 1; } if (g.isEdge(vertArray[1], vertArray[1])) { System.out.println("isEdge(vertex 1, vertex 1) should return false " + " but returns true."); remVDeduction = 1; } result = g.degree(vertArray[1]); if (result != 0) { System.out.println("degree(vertex 1) returns " + result + " but should return 0."); remVDeduction = 1; }

System.out.println("Removing edge (7, 6)."); g.removeEdge(vertArray[7], vertArray[6]); System.out.println("Removing edge (3, 1)."); g.removeEdge(vertArray[3], vertArray[1]); System.out.println("Removing edge (1, 1)."); g.removeEdge(vertArray[1], vertArray[1]); result = g.edgeCount(); if (result != 2) { System.out.println("edgeCount() returns " + result + " but should return 2."); remVDeduction = 1; } if (g.isEdge(vertArray[1], vertArray[1])) { System.out.println("isEdge(vertex 1, vertex 1) should return false " + " but returns true."); remVDeduction = 1; }

System.out.println("Removing edge (9, 7)."); g.removeEdge(vertArray[9], vertArray[7]); result = g.edgeCount(); if (result != 1) { System.out.println("edgeCount() returns " + result + " but should return 1."); remVDeduction = 1; } if (g.isEdge(vertArray[9], vertArray[7])) { System.out.println("isEdge(vertex 9, vertex 7) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[7], vertArray[9])) { System.out.println("isEdge(vertex 7, vertex 9) should return false " +

Page 147: java book

" but returns true."); remVDeduction = 1; }

System.out.println("Removing vertex 9."); g.removeVertex(vertArray[9]); result = g.vertexCount(); if (result != 8) { System.out.println("vertexCount() returns " + result + " but should return 8."); remVDeduction = 1; } result = g.edgeCount(); if (result != 0) { System.out.println("edgeCount() returns " + result + " but should return 0."); remVDeduction = 1; } if (g.isEdge(vertArray[9], vertArray[0])) { System.out.println("isEdge(vertex 9, vertex 0) should return false " + " but returns true."); remVDeduction = 1; } if (g.isEdge(vertArray[0], vertArray[9])) { System.out.println("isEdge(vertex 0, vertex 9) should return false " + " but returns true."); remVDeduction = 1; } result = g.degree(vertArray[9]); if (result != 0) { System.out.println("degree(vertex 9) returns " + result + " but should return 0."); remVDeduction = 1; } result = g.degree(vertArray[0]); if (result != 0) { System.out.println("degree(vertex 0) returns " + result + " but should return 0."); remVDeduction = 1; }

System.out.println(); return countDeduction + degreeDeduction + 2 * getDeduction + isDeduction + weightDeduction + 2 * remEDeduction + 2 * remVDeduction;

}

public static final int VERTICES = 20;

public static void main(String[] args) { int i;

Object vertArray[] = new Object[VERTICES]; for (i = 0; i < VERTICES; i++) {

Page 148: java book

vertArray[i] = new Nothing(); }

int score = 14 - vertexTest(vertArray) - edgeTest(vertArray); if (score < 0) { score = 0; }

System.out.println("Your WUGraph test score is " + (0.5 * (double) score) + " out of 7.0."); System.out.println(" (Be sure also to run KruskalTest.java.)"); }}

class Nothing {}


Recommended