Due Date: Thursday, April 18, 2024, 11:59pm PST
There is an FAQ post on Piazza. Please read that post first if you have any questions.
- Implement a data structure similar to Java’s ArrayLists with generic types
- Write JUnit tests to verify proper implementation
In this part of the assignment, you will implement a data structure similar to Java's ArrayList and write JUnit tests to ensure that your implementation functions correctly.
Make sure to read the entire write-up before you start coding.
Download the starter code and put it in a directory in your working environment.
You will find the following files:
+-- PA2/starter
| +-- MyList.java
| +-- MyArrayListPublicTester.java
| +-- MyArrayListHiddenTester.java Edit this file
| +-- MyArrayList.java (create this file) Edit this file
Running the tester on UNIX based systems (including a mac):
- Compile:
javac -cp ../libs/junit-4.13.2.jar:../libs/hamcrest-2.2.jar:. MyArrayListPublicTester.java
- Execute:
java -cp ../libs/junit-4.13.2.jar:../libs/hamcrest-2.2.jar:. org.junit.runner.JUnitCore MyArrayListPublicTester
Running the tester on Windows systems:
- Compile:
javac -cp ".;..\libs\junit-4.13.2.jar;..\libs\hamcrest-2.2.jar" MyArrayListPublicTester.java
- Execute:
java -cp ".;..\libs\junit-4.13.2.jar;..\libs\hamcrest-2.2.jar" org.junit.runner.JUnitCore MyArrayListPublicTester
To run the hidden tester, replace references to MyArrayListPublicTester
with MyArrayListHiddenTester
in the above commands.
We provide two test files:
MyArrayListPublicTester.java
- Contains all the public test cases we will use to grade your MyArrayList implementation (visible on Gradescope)
MyArrayListHiddenTester.java
- Contains only the headers and description to the hidden test cases we will use to grade your MyArrayList implementation (hidden until the PA is graded)
Your task: Implement the missing unit tests in MyArrayListHiddenTester.java based on the description in ‘hidden tests’ column in the Tests table below.
- Your tests will be graded to check if they pass/ fail correctly
- NOTE: DO NOT CHANGE THE TEST HEADERS!
Tests Table: List of various test cases and their description
Test Cases | Public Tests | Hidden Tests (Implement these) |
Constructors
|
MyArrayList objects instantiated with the three different constructors should have the correct properties specified. If the argument passed into the constructor is invalid, throw the correct exception.
|
|
append
|
Test if an element is correctly inserted at the end of the ArrayList, while preserving existing elements. Size and capacity should be updated to reflect the change to the ArrayList where applicable.
|
|
prepend
|
Test if an element is correctly inserted at the beginning of the ArrayList, while preserving existing elements. Size and capacity should be updated to reflect the change to the ArrayList where applicable.
|
|
insert
|
Test if an element is inserted at the correct location and if size and capacity are updated appropriately to account for the newly inserted element.
|
|
get
|
Test if the value returned is correct. Size and capacity should remain unchanged.
|
|
set
|
Test if the element is changed correctly. Size and capacity should remain unchanged.
|
|
remove
|
Test if the correct element is removed. Capacity remains unchanged.
|
|
size
|
Test if the correct size is returned. The ArrayList should remain unchanged after call to size() .
|
|
expandCapacity
|
Test if capacity is expanded appropriately.
|
|
getCapacity
|
Test that the correct capacity size is being returned for an empty and populated ArrayList . The ArrayList should remain unchanged after the call to getCapacity() .
|
|
rotate
|
Test if the list is rotated correctly. Size and capacity should remain unchanged.
|
|
find
|
Test if the index returned is correct. Size and capacity should remain unchanged.
|
|
In this part of the assignment, you will create your own implementation of ArrayList called MyArrayList.
DO NOT IMPORT AND USE JAVA'S BUILT IN ARRAYLIST or any other imports!!! If we see that you do use these functions, you will receive a zero. You must implement the ArrayList from scratch to earn credit for this assignment.
- Edit the file named MyArrayList.java. Make sure the MyArrayList class implements MyList. MyArrayList is a generic class. This class will only be a subset of the Java Collection’s Framework ArrayList.
- Your task is to implement the instance variables, constructors and public methods stubbed out in the interface and described in the table below.
- There are various ways to implement an ArrayList. In PA2, you will follow these:
Note: Do not make these instance variables private, they should have the default access modifier (i.e. do not declare them as public or private). Do not add any other instance variables and static variables other than private static final variables to be used as constants. There are two instance variables.
-
Object[] data
:The underlying data structure of the ArrayList. The index of an element in this array should correspond to the index of the element in the ArrayList.
- You don't need to check if
data
isnull
in any of your code. You can assumedata
will never benull
. null
can be a valid element in your ArrayList. The only way of knowing if an element is valid or not is by checking thesize
variable, defined below. All invalid elements in the array should benull
. Check the Example with nulls for more clarity.- Note: In some of the methods you will write, you will need to return an object of type
E
, but ourdata
array is of typeObject
, so we will need to cast whatever we return to typeE
(e.g.,(E) data[0]
). If you compile with code that does this, you will see the following warning.
- You don't need to check if
The code will still work exactly the same, but if you want to hide this warning, add @SuppressWarnings("unchecked")
above any method that does this cast
int size
:
This variable should be equal to the number of valid elements in yourdata
array. A valid element indata
is an element in your ArrayList.- Note: You may assume that nothing (other than possibly your own code) would change
size
to be something out of bounds ofdata
(i.e.,size >= 0 && size <= data.length
will always evaluate totrue
, unless your code manually sets it to be something else).
- Note: You may assume that nothing (other than possibly your own code) would change
There are three constructors.
public MyArrayList()
:
Initialize the Object array with the default length of 5. The capacity of the ArrayList is the length of the array.- Note: the capacity (length of
data
:data.length
) is ==not== the same as the size (number of elements in the ArrayList, i.e., the number of valid elements in the array)
- Note: the capacity (length of
public MyArrayList(int initialCapacity)
: Initialize the Object array with the length ofinitialCapacity
. If theinitialCapacity
is invalid (i.e. any value ofinitialCapacity
strictly less than 0), throw anIllegalArgumentException
.public MyArrayList (E[] arr)
:
Initialize the instance variables with a copy of the input array of capacity equal to the length ofarr
. All elements inarr
are valid (even thenull
s), so setsize
accordingly. Ifarr
isnull
, fall back to the behavior of the no-arg constructor (construct an ArrayList with the default capacity).
Note: Do not make these functions private, they should all remain public (for testing and grading purposes). There are eleven methods.
The following table includes all the methods you need to implement in MyArrayList.java
Method Name | Description | Example | Exceptions to Throw |
---|---|---|---|
public void expandCapacity (int requiredCapacity) |
If the current capacity is non-zero, double the current capacity. If the current capacity is 0, reset the capacity to the default capacity of 5. If the capacity is still not enough, then set the capacity to requiredCapacity. This method should preserve the current size and elements in the list (the elements before and after expansion should be at the same indices respectively). | If the current capacity is 3 and requiredCapacity is 4, the capacity afterward should be 6. If the current capacity is 3 and requiredCapacity is 18, then capacity should be set to 18 (because |
Throw an IllegalArgumentException when requiredCapacity is strictly less than the initial capacity. |
public int getCapacity() |
Get the number of elements that the underlying array can possibly hold, i.e. the length of the underlying array. | None. | None. |
public void insert(int index, E element) |
Insert an element at the specified index. If the array is at capacity before insertion, update the capacity according to expandCapacity() 's rules. You may want to take a look at the expandCapacity() method. |
If the list is{1,2,3} and you insert 4 at index 2, the resulting list will be {1,2,4,3} . If the list is initially empty {}, and you insert 4 at index 0, the resulting list will be {4} . |
Throw an IndexOutOfBoundsException when the index is strictly less than 0 or strictly greater than the size of the ArrayList. |
public void append(E element) |
Add an element at the end of the list. If the array is at full capacity, update the capacity according to expandCapacity() 's rules. |
If the list is {1,2,3} and you append 4, the resulting list will be {1,2,3,4} . If the list is empty and you append 4, the resulting list should be {4}
|
None. |
public void prepend(E element) |
Add an element at the beginning of the list. If the array is at capacity, update the capacity according to expandCapacity() 's rules. |
If the list is {1,2,3} and you prepend 4, the resulting list will be {4,1,2,3} . If the list is empty and you prepend 4, the resulting list should be {4} . |
None. |
public E get(int index) |
Get an element at the specified index. | If the list is {1,2,3} , getting elements at index 2 should return 3. |
Throw an IndexOutOfBoundsException when the index is strictly less than 0 or greater than or equal to the size of the ArrayList . |
public E set(int index, E element) |
Set the given element at the specified index and return the overwritten element. | If the list is {1,2,3} and you set element at index 1 to be 4, the resulting list will be {1,4,3} . |
Throw an IndexOutOfBoundsException when the index is strictly less than 0 or greater than or equal to the size of the ArrayList . |
public E remove(int index) |
Remove and return the element at the specified index. | If the list is {1,2,3} and you remove element at index 1, the resulting list will be {1,3} . |
Throw an IndexOutOfBoundsException when the index is strictly less than 0 or greater than or equal to size of the ArrayList . |
public int size() |
Return the number of elements that exist in the ArrayList
|
None. | None. |
public void rotate(int index) |
Rotates each element in the ArrayList left by index amount. The element previously at index should be the first element in the list after this operation. |
If the list is {1,2,3,4} and you shift left by 3, the resulting list will be {4,1,2,3} . |
Throw an IndexOutOfBoundsException when the index is strictly less than 0 or greater than or equal to the size of the ArrayList . |
public int find(E element) |
Find the given element in the ArrayList and return it's index. If there are multiple occurrences of the element, return the index of the first occurrence of that element. If the element is not in the ArrayList , return -1 |
If the list is {1, 2, 3, 2} , find(3) should return 2, find(2) should return 1, and find(4) should return -1. |
None. |
As stated earlier, null
can be a valid element in your ArrayList. In this example, bolded elements are elements in the ArrayList (valid elements of data
) and non-bolded null
represent unoccupied spots in data
.
Statements on the left-hand side of the array should evaluate to expressions on the right-hand side.
... list.data -> [3, 1, null, 5, null, null, null] // capacity is 7 list.size() -> 5 list.append(20); list.size() -> 6 list.data -> [3, 1, null, 5, null, 20, null] list.append(null); list.size() -> 7 list.data -> [3, 1, null, 5, null, 20, null] // capacity is still 7 list.remove(6) -> null list.size() -> 6 list.data -> [3, 1, null, 5, null, 20, null] list.remove(5) -> 20 list.size() -> 5 list.data -> [3, 1, null, 5, null, null, null] list.remove(4) -> null list.size() -> 4 list.data -> [3, 1, null, 5, null, null, null] list.remove(3) -> 5 list.size() -> 3 list.data -> [3, 1, null, null, null, null, null] list.remove(2) -> null list.size() -> 2 list.data -> [3, 1, null, null, null, null, null] list.remove(1) -> 1 list.size() -> 1 list.data -> [3, null, null, null, null, null, null] list.remove(0) -> 3 list.size() -> 0 list.data -> [null, null, null, null, null, null, null]
... list.data -> [null, 1, null, null, 2, 3, null, null] // capacity is 8 list.size() -> 6 list.rotate(1) list.data -> [1, null, null, 2, 3, null, null, null] list.rotate(2) list.data -> [null, 2, 3, null, 1, null, null, null]
Coding style is an important part of ensuring readability and maintainability of your code. We will grade your code style in all submitted code files according to the style guidelines. Namely, there are a few things you must have in each file/class/method:
- File header
- Class header
- Method header(s)
- Inline comments
- Proper indentation
- Descriptive variable names
- No magic numbers (Exception: Magic numbers can be used for testing.)
- Reasonably short methods (if you have implemented each method according to the specification in this write-up, you’re fine). This is not enforced as strictly.
- Lines shorter than 80 characters
- Javadoc conventions (
@param
,@return
tags,/** comments */
, etc.)
A full style guide can be found here and a sample styled file can be found here. If you need any clarifications, feel free to ask on Piazza.
Please follow ALL of the instructions below to completely submit your assignment.
- Submit all of the following files to Gradescope.
- MyArrayListHiddenTester.java
- MyArrayList.java
- Coding Style (5 points)
- Correctness (95 points) You will earn points based on the autograder tests that your code passes. If the autograder tests are not able to run (e.g., your code does not compile or it does not match the specifications in this writeup), you may not earn credit.
- Tester (20 points)
- The autograder will test your implementation of the Junit tests. Your unit tests are expected to fail or pass based on the
test cases
table’shidden tests
column in Part 1.
- The autograder will test your implementation of the Junit tests. Your unit tests are expected to fail or pass based on the
- MyArrayList (75 points)
- The autograder will test your implementation of MyArrayList on both public and hidden test cases listed in the table
- Tester (20 points)