The second assignment is mostly about arrays, notably our own array specifications and implementations, not just the built-in Java arrays. First, we will re-visit the
Unique program but with our own
Array implementation. Then you will be programming a different implementation of our
Note: This assignment we will require your Java source to be checkstyle compliant with the provided configuration file! You will lose 1 point for each type of checkstyle violation; excessive instances of the same type of violation might be docked extra.
This assignment has a slightly more advanced package setup. Now we have two subpackages. This setup will provide you with files exactly how they exist in the autograder.
Files you will be editing are marked with an asterisk (*).
hw2-student.zip -- exceptions/ IndexException.java LengthException.java hw2/ Array.java ListArray.java PolyArray.java * SimpleArray.java SparseArray.java * Unique.java *
These provided files should compile as is. You can compile everything by running
$ javac -Xlint:all hw2/*.java exceptions/*.java, or using the generic compile script from the Java Command Line notes. You should only need to compile
exceptions/*.java one time.
You wrote a small Java program called
Unique for Assignment 1 which got it’s input in the form of command line arguments and printed each unique integer it received back out once, eliminating duplicates in the process.
For this problem, you will implement a new version of
Unique. Note that this will be the
hw2 package version of
Unique so you can distinguish between the two even though they have the same name (running
hw2.Unique is different from running
hw1.Unique). This new version will have two major changes:
First, you are no longer allowed to use Java arrays (nor any other advanced data structure), but you can use our
Array interface and our
SimpleArray implementation provided in the zip.
Second, you’re going to modify the program to read the integers from standard input instead of processing the command line.
So the resulting
Unique program is invoked as
$ java hw2.Unique
with no further arguments (or rather, the program ignores any arguments the user passes to it). The program then waits for input from the user, who could for example type
1 9 2 3 1 4 9 5 3 6 0
and then hit the end-of-file (EOF) key - that’s CTRL-D on Unix and CTRL-Z on Windows. At this point the program should output the unique numbers that were present in the input just like before:
1 9 2 3 4 5 6 0
Note, like before the output numbers dont need to be sorted, and non-integer values should be treated as before and cause an exception. The files
SimpleArray.java are in the
Please use those official files and do not edit them - the autograder will replace those files with the unedited version anyways.
In your README, you should address the following: 1. Discuss your approach to doubling the array.
Make sure you hit return one last time at the end of your input and only then signal end-of-file with the appropriate key-combination for your operating system. (This restriction doesn’t apply when you use I/O redirection to give input to the program, a highly recommended practice for testing).
End-of-file in a unix/linux environment is usually ctrl-d, but it’s ctrl-z in a windows environment. In Intellij, take a look here for more information.
You will have to process an unbounded number of inputs, which requires that you keep track of how “full” the array is. When nothing fits into the array anymore, you’ll have to “grow” it somehow. The best approach is to double the size of the array when you are out of space.
Do not try to change everything at once, there are too many “moving parts” to get things right that way. Instead, choose one thing to change,for example just the way input is given to the program, finish that, test it, and only then move on to the next thing. Remember: Baby steps!
Ideally, the type of your object holding the data should be the interface class, an
Array<Integer>. This way you can swap out the implementation just by changing which array you instantiate. Note the type of an
Array must be an object and cannot be a primitive type,
Array<int> is invalid in Java.
A sparse array is an array in which relatively few positions have values that differ from the initial value set when the array was created. For sparse arrays, it is wasteful to store the value of all positions explicitly since most of them never change and take the default value of the array. Instead, we want to store positions that have actually been changed.
For this problem, write a class
SparseArray that implements the
Array interface we developed in lecture (the same interface you used for Part A above). Do not modify the
Array interface in any way! Instead of using a plain Java array like we did for
SparseArray should use a linked list of
Node objects to store values, similar to the
ListArray in the
hw2 package. However, your nodes no longer store just the data at a certain position, they also store the position itself!
Here’s a rough outline of how your implementation could work:
Start with an empty list (instead of the complete list we built in the constructor of
put, check if the relevant position has been modified before (meaning a
Node object exists for that position); if not, add a
Node to the list for the position and its new value; otherwise update the correct
Node to the new value.
get, check if the relevant position has been modified before; if not, return the default value; otherwise, return the value found in the relevant
Node class must be nested inside your
SparseArray class with
private visibility! Clients should not be able to “touch”
Node objects in any way!
Make sure your Javadoc comments include advice for clients trying to decide between the regular
SimpleArray implementation and your new sparse implementation.)
As part of Assignment 1, we gave you a program called
PolyCount that could be used to test the basic operation of a number of different
For this assignment, we’re giving you a similar program called
PolyArray that can be used to test array implementations (some of the details are a bit more complex for technical reasons, but you don’t need to understand those for now).
PolyArray is far from complete regarding test cases:
the code in
testNewLength only covers 1 axiom of the specification
the code in
testNewLengthWrong only covers the 1 precondition of the specification
You need to modify
PolyArray.java to add more test cases so that the entire implementation is tested.
Of course, you should also use
PolyArray to test your new
SparseArray code. Once you’re done with
PolyArray all three implementations should be fully tested when the program is run.
Make sure in your final deliverable you pass your own tests from this file as we will be checking this in the autograder.
In your README, you should address the following: 1. When would a
SparseArray be useful and why? 2. Why is it that
SparseArray must implement
Your iterator for
SparseArray doesn’t have to be particularly efficient; indeed, it’s rather tricky to make it work fast; don’t try. (Or rather: Only try if you’re bored!)
Arrayto look like. You don’t just iterate over your own list (i.e. copying the iterator from
Think about this: Someone creates a
SparseArray<Integer> with an initial value of 1. Then they put a few numbers different from 1 into the array. For example, the value of slot 4 might be 18. What should happen for
Testing a precondition means testing that the correct exception is thrown when a bad parameter is provided.
Note that the
PolyArray we gave you doesn’t test iterators at all; it probably should since all array implementations (the ones we gave you and the one you wrote yourself) support iterators…
SimpleArray has one inevitable unchecked cast warning. When you compile, this one warning is fine, but your own code should not add any additional warnings.
The files you have
// TODO items in are listed explicitly below:
Unique.java SparseArray.java PolyArray.java
You need to submit all of these files to the autograder along with a README. You can upload them individually or in a zip file. If you upload them in a zip file make sure they are all at the top level, you cannot have any extra directories or else the autograder won’t be able to find them.
Make sure the code you hand in does not produce any extraneous debugging output. If you have commented out lines of code that no longer serve any purpose you should remove them.
You must hand in the source code and a README file. The README file can be plain text (
README with no extension), or markdown (
README.md). In your README be sure to answer the discussion questions posed in this description. You should discuss your solution as a whole and let the staff know anything important. If you are going to be using late days on an assignment, we ask that you note it in your README.
If you want to learn markdown formatting, here is a good starting point.
Once you are ready to submit your files, go to the assignment 2 page for Gradescope and click submit. Note that you can resubmit any time up until the deadline. Only your most recent submission will be graded. Please refer to course policies as far as policies regarding late days and penalties.
After you submit, the autograder will run and you will get feedback on your functionality and how you performed on our test cases. Some test cases are “hidden” from you so you won’t actually know your final score on the test cases until after grades are released. We also include your checkstyle score as a test case.
If you see the “Autograder Failed to Execute” message, then either your submission did not compile at all or there was a packaging error. Please see the Gradescope Submission Notes for help debugging why your submission is not working.
You do not need to fully implement each file before you submit, but you’ll probably fail the test cases for the parts of the assignment you haven’t done yet. Also note that only the files with
// TODO items in them will be used. You cannot modify any of the provided interface files as the autograder will overwrite any changes you made with the original provided file.
For reference, here is a short explanation of the grading criteria; some of the criteria don’t apply to all problems, and not all of the criteria are used on all assignments.
Packaging refers to the proper organization of the stuff you hand in, following both the guidelines for Deliverables above as well as the general submission instructions for assignments.
Style refers to Java programming style, including things like consistent indentation, appropriate identifier names, useful comments, suitable
javadoc documentation, etc. Many aspects of this are enforced automatically by Checkstyle when run with the provided configuration file.
privateappropriately, etc.). Simple, clean, readable code is what you should be aiming for.
Testing refers to proper unit tests for all of the data structure classes you developed for this assignment, using the JUnit 4 framework as introduced in lecture. Make sure you test all parts of the implementation that you can think of and all exception conditions that are relevant.
Performance refers to how fast/with how little memory your program can produce the required results compared to other submissions.
Functionality refers to your programs being able to do what they should according to the specification given above; if the specification is ambiguous and you had to make a certain choice, defend that choice in your
If your submission does not compile, you will not receive any of the autograded-points for that assignment. It is always better to submit code that at least compiles. You will get freebie points just for compiling.
If your programs have unnecessary warnings when using
javac -Xlint:all you will be penalized 10% functionality per failed part. (You are also unable to use the
@SuppressWarnings annotation - we use it just to filter our accepted warnings from yours.)
If your programs fail because of an unexpected exception, you will be penalized 10% functionality per failed part. (You are not allowed to just wrap your whole program in to a universal try-catch.)