Java Book
Java Book
Midterm I
Solutions
• 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).
• 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.
a. m returns 5
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.
d.
a. 3, 4, 5, and 6.
b. Advantages of a binary search tree over a hash table (any one will suffice):
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.)
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.)
a.
Because f(n) is in Theta(j(n)), f(n) is in Omega(j(n)), so there exist positive constants c1,
N1 such that
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.
• 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;''.
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.
• 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;''.
a. The minimax algorithm could be said to be using either a preorder or a postorder tree
traversal. (Either answer was accepted as correct.)
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.
a.
b.
c.
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 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 and
2) Ends with insert(2) or find(2) is correct
g.
Worse: 19 bytes
Only in the latter case can the memory formerly occupied by W objects
be reused
for X objects.
Problem 2:
a.
X 3 4 5 5 12 8 9 7
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 5
3 8 1 0 7 5 9 5
3 0 1 8 7 5 9 5
3 0 1 5 7 5 9 8
0 3 1 5 7 5 9 8
0 1 3 5 7 5 9 8
0 1 3 5 7 5 8 9
0 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.
For each item in SMALLER set, check if it's in larger set using hash
table. 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:
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
/ \ \
2 4 findElement(1) 2
/ \ -------------> \
1 5 3
\
4
\
5
c.
(log n)
k * -------
(log k)
or
k log n
problem 3:
a.
7 4 2 8 1 0 6 3
4 7 2 8 1 0 6 3
4 7 2 8 0 1 6 3
4 7 2 8 0 1 3 6
2 4 7 8 0 1 3 6
0 1 2 3 4 6 7 8
mergesort
b.
7 4 2 8 1 0 6 3
0 4 2 8 1 7 6 3
0 1 2 8 4 7 6 3
0 1 2 3 4 7 6 8
0 1 2 3 4 6 7 8
selection sort
c.
7 4 2 8 1 0 6 3
4 2 8 0 6 7 1 3
4 8 0 1 2 6 7 3
8 0 1 2 3 4 6 7
0 1 2 3 4 6 7 8
radix sort
d.
7 4 2 8 1 0 6 3
4 7 2 8 1 0 6 3
2 4 7 8 1 0 6 3
1 2 4 7 8 0 6 3
0 1 2 4 7 8 6 3
0 1 2 4 6 7 8 3
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
/ | \ / \
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's
children point to its parent. If ITEM is a root, choose arbitrary child
to be
new root; make other children point to it.
d.
One possibility:
Use a general sibling-based tree data structure, but make siblings be
doubly-linked so path compression is fast.
Another possibility:
Each set's root references a linked list of all the items in the set
(which
does NOT need to be doubly linked). When sets are unioned, these lists
are
concatenated. 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 x
can be changed by foo().
c.
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
n n n
Sum (sqrt(i)) >= Sum (sqrt(i)) >= Sum (sqrt(ceil(n/2))) >=
i=1 i=ceil(n/2) i=ceil(n/2)
OR
Problem 8:
int index = 0;
for (int i = 0; i < range; i++) {
for (int j = 0; j < counts[i]; j++) {
sorted[index] = i;
index++;
}
}
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).
[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
[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.
-----
[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|
-----
--- ---
[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?
[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).
[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.
Programming questions.
[18] Rewrite the quicksort() method from the Lecture 31 notes in C++.
The
signature should appear as follows.
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.
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.
/* OpenCommercial.java */
import java.net.*;
import java.io.*;
/** 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;
}
}
/* 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) {
/** 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
}
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));
}
}
/* Date.java */
import java.io.*;
class Date {
/** 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) {
/** 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);
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));
}
}
/* 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
**/
/**
* 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.
**/
/**
* length() returns the length of this list.
* @return the length of this list.
**/
/**
* 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);
size++;
}
/**
* insertEnd() inserts item "obj" at the end of this list.
* @param obj the item to be inserted.
**/
/**
* 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.
**/
/**
* 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
* 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.
**/
/**
* 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.
**/
/**
* toString() converts the list to a String.
* @return a String representation of the list.
**/
/**
* 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.
**/
/**
* 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.
**/
/**
* testAfterInsertEnd() tests toString(), isEmpty(), length(),
* insertFront(), and insertEnd() after insertEnd(). Prints summary
* information of the tests and halts the program if errors are
detected.
**/
/* 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".
*/
}
/* 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.
**/
/**
* 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.
**/
}
/* 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.
*/
/* You may renumber these constants if you wish, but don't rename
them. */
/**
* 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.
*/
/**
* width() returns the width of an Ocean object.
* @return the width of the ocean.
*/
/**
* height() returns the height of an Ocean object.
* @return the height of the ocean.
*/
/**
* starveTime() returns the shark starveTime of an Ocean object.
* @return the shark starveTime.
*/
/**
* 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.
*/
/**
* 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.
*/
/**
* 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.
*/
/**
* timeStep() performs a simulation timestep as described in README.
* @return an ocean representing the elapse of one timestep.
*/
/**
* 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.
*/
/**
* 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.
*/
/* 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.
*/
/**
* 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.
*/
/**
* width() returns the width of an Ocean object.
* @return the width of the ocean.
*/
/**
* height() returns the height of an Ocean object.
* @return the height of the ocean.
*/
/**
* starveTime() returns the shark starveTime of an Ocean object.
* @return the shark starveTime.
*/
/**
* 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.
*/
/**
* 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.
*/
/**
* timeStep() performs a simulation timestep as described in README.
* @return an ocean representing the elapse of one timestep.
*/
/**
* 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.
*/
/**
* 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.
*/
}
/* 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.
*/
/**
* Define any variables associated with a RunLengthEncoding object
here.
* These variables MUST be private.
*/
/**
* 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.
*/
/**
* 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.
*/
/**
* 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
* 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.
*/
/**
* 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.
*/
/**
* 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.
*/
/**
* 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.
*/
/**
* 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.
*/
/**
* 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
* 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.
*/
/**
* 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.
*/
/* SimText.java */
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
* 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
*/
/**
* Default parameters. (You may change these if you wish.)
*/
/**
* paint() prints an Ocean.
*/
/**
* main() reads the parameters and performs the simulation and
animation.
*/
/**
* 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.
*/
/**
* Perform timesteps forever.
*/
}
/* Simulation.java */
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
*/
/**
* The constant cellSize determines the size of each cell on the
screen
* during animation. (You may change this if you wish.)
*/
/**
* 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
/**
* main() reads the parameters and performs the simulation and
animation.
*/
/**
* 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 {
/**
* 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.
*/
/* 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() {
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.
}
/**
* 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.
}
/**
* 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 + "]";
}
/* DListNode.java */
package list;
/**
* A DListNode is a node in a DList (doubly-linked list).
*/
/**
* 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.
*/
/**
* 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().
**/
/**
* 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.
}
/**
* 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 "";
}
s.union(s2);
System.out.println("After s.union(s2), s = " + s);
s.intersect(s3);
System.out.println("After s.intersect(s3), s = " + s);
/* 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.
**/
/**
* (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.
**/
/* 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 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.
}
/**
* 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 + "]";
}
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.");
}
}
}
/* DListNode.java */
package list;
/**
* A DListNode is a mutable node in a DList (doubly-linked list).
**/
/**
* (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.
**/
/**
* 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;
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
* 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.
*/
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.
/* InvalidNodeException.java */
package list;
/**
* Implements an Exception that signals an attempt to use an invalid
ListNode.
*/
protected InvalidNodeException(String s) {
super(s);
}
}
/* List.java */
package list;
/**
* A List is a mutable list ADT. No implementation is provided.
*
* DO NOT CHANGE THIS FILE.
**/
/**
* size is the number of items in the list.
**/
/**
* 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.
*
* @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.
**/
/**
* item references the item stored in the current node.
* myList references the List that contains this node.
*
* DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS.
*/
/**
* 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.
*
* @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;
/**
* 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.
**/
/**
* (inherited) size is the number of items in the list.
* head references the first node.
* tail references the last node.
**/
/* SList invariants:
* 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.
*
* 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.
*
* @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 + "]";
}
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).
**/
/**
* (inherited) item references the item stored in the current node.
* (inherited) myList references the List that contains this node.
* next references the next node in the SList.
*
* DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS.
**/
/**
* 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()) {
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 {
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--;
/* Homework6Test.java */
import dict.*;
/**
* Initializes a hash table, then stocks it with random SimpleBoards.
* @author Daniel C. Silverstein
**/
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));
}
}
if (args.length == 0) {
numBoards = 100;
} else {
numBoards = Integer.parseInt(args[0]);
}
HashTableChained table = new HashTableChained(numBoards);
initTable(table, numBoards);
/* SimpleBoard.java */
/**
* 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.
*/
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.
*
* @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.
* 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.
*
* @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;
}
/**
* 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 {
// Creates a machine player with the given color. Color is either 0
(black)
// or 1 (white).
// 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) {
}
/* Move.java */
package player;
/**
* 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 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.
/* 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;
}
/* 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
*/
/**
* size is the number of items in the dictionary.
**/
/**
* 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;
}
}
/* 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 "";
} 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)) {
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.");
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 */
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;
/**
* 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.
**/
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 {
/**
* 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;
/**
* 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;
tAccum = 0;
}
}
/* ListSorts.java */
import list.*;
/**
* 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
* 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())));
}
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);
stopWatch.reset();
q = makeRandom(SORTSIZE);
stopWatch.start();
quickSort(q);
stopWatch.stop();
System.out.println("Quick sort time, " + SORTSIZE + " Integers: " +
stopWatch.elapsed() + " msec.");
*/
}
/* LinkedQueue.java */
package list;
/**
* 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);
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;
q.tail = null;
q.size = 0;
}
/* Queue.java */
package list;
/**
* 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;
}
/* QueueEmptyException.java */
package list;
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
* 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".
*/
/* Maze.java */
import java.util.*;
import set.*;
/**
* The Maze class represents a maze in a rectangular grid. There is
exactly
* one path between any two points.
**/
/**
* 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
}
/**
* 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 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
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
}
if (mazeFine) {
System.out.println("What a fine maze you've created!");
}
}
/**
* 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;
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.");
}
}
}
/* 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
**/
/**
* 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
}
}
/**
* 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;
package sort;
/**
* 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) {
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 */
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.
*/
/* 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;
/**
* 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;
}
}
}
/* WUGraph.java */
package graph;
import java.util.Hashtable;
/**
* The WUGraph class represents a weighted, undirected graph. Self-
edges are
* permitted.
*/
/**
* 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
* 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.
* 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;
/**
* 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
**/
/**
* 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
}
}
/**
* 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;
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.
*/
/**
* 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.*;
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;
}
}
}
}
addRandomEdges(g, vertArray);
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;
}
class DFSVertex {
boolean visited;
int number;
}
/* WUGTest.java */
/**
* The WUGTest class tests the WUGraph class.
*/
import graph.*;
System.out.println();
return countDeduction + 2 * getDeduction + isVDeduction;
}
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;
}
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;
}
System.out.println();
return countDeduction + degreeDeduction + 2 * getDeduction +
isDeduction +
weightDeduction + 2 * remEDeduction + 2 * remVDeduction;
class Nothing {
}