Summary. Many real-world applications rely on processing of large 2D matrices that often
have few non-zero elements relative to the total number of entries in the matrix. For Project #3,
you will use linked lists to implement a memory-efficient, sparse 2-dimensional matrix data
structure. Then, you will test your data structure by loading in some large 800×800 matrices,
which we have constructed to contain hidden patterns that will be visible if you have
implemented your matrix correctly.
Overview of a Linked List Sparse Matrix Data Structure Design.
A typical linked list implementation of a sparse matrix relies on two sets of interconnected linked
lists: one for the rows of the matrix, and one for the columns of the matrix. On both sides, an
array can be used to keep track of the heads of each linked list, and each element is part of one
column linked list as well as one row linked list. An example of the logical structure a linked list
is shown below for a 5×5 matrix (Figure A).
Each of the matrix elements will need to store their data, row and column indices, and two links:
one to the next element in that column (if it exists) and one to the next element in that row (if it
exists) (Figure B). The data for the element (1,0) of the sparse matrix is shown as an example
in Figure C. Your goal will be to implement a class MatrixEntry that stores all of this information
as well as a class SparseIntMatrix that implements the linked list structure shown above.
Part I. (20 points) Defining and Implementing a MatrixEntry class
The MatrixEntry class contains all of the data members necessary for storing the data and links
for each element of the sparse matrix. Define and implement this class including the following
● MatrixEntry(int row, int col, int data) (constructor); input: the row, column, and data
associated with this matrix element; output: an instance of the MatrixEntry class
● int getColumn(); input: none; output: an integer corresponding to the column of this entry
● void setColumn(int col); input: integer corresponding to the column of this entry; output:
● int getRow(); input: none; output: an integer corresponding to the row of this entry
● void setRow(int row); input: integer corresponding to the row of this entry; output: none
● int getData(); input: none; output: an integer corresponding to the data associated with
● void setData(int data); input: integer with the data for this matrix entry; output: none:
● MatrixEntry getNextRow(); input: none; output: output: a MatrixEntry reference for this
entry’s next row. (The next row is defined as the element with the same column number,
and a different row number)
● void setNextRow(MatrixEntry el); input: MatrixEntry reference of this entry’s next row;
output; output: none
● MatrixEntry getNextCol(); input: none; output: a MatrixEntry reference for this entry’s
next column. (The next col is defined as the MatrixEntry element with the same row
number, and a different col number)
● void setNextCol(MatrixEntry el); input: MatrixEntry reference of this entry’s next column;
Data members: any that are necessary to maintain the object’s state and implement the
methods above. The MatrixEntry class should be defined as a separate class from the
SparseIntMatrix class described below, and all data members should be declared private. Your
SparseIntMatrix class client should interact with MatrixEntry objects through the public
Part II. (10 points) Writing Unit Tests for MatrixEntry
Before you implement your SparseIntMatrix class, you will need to write unit tests, using JUnit,
to ensure your MatrixEntry class is working as expected. You are required to implement at least
four unit tests, but are free to write more than that if you wish. Please write the tests in a java file
named MatrixEntryTest.java The unit tests need to assert the following features:
● The MatrixEntry constructor properly initializes the row, column, and data member
● setRow(), setCol(), and setData() properly update the MatrixEntry’s row, column, and
● setNextColumn() updates the correct MatrixEntry reference variable, and
getNextColumn() returns the correct MatrixEntry reference variable.
● setNextRow() updates the correct MatrixEntry reference variable, and getNextRow()
returns the correct MatrixEntry reference variable.
You are free (and encouraged) to use existing JUnit tests we have provided you for this project
as well as previous projects and labs as a resource for creating your testing class.
Hint: Because the row, col, data, nextRow, and nextCol variables in your MatrixEntry class must
be private, you will need to use your getter methods (i.e. getRow() and getCol()) to ensure the
appropriate setter methods are working).
Part III. (50 points) Defining and Implementing a SparseIntMatrix class
Your third goal is to design and implement the SparseIntMatrix class, which should provide the
basic functionality of a matrix, but use the linked list structure described above (NOTE: you
should not just use a 2D array here—you will receive 0 points for a 2D array-based solution,
however you may use two single dimension arrays as shown in the overview).
Note: For full credit, you must keep properly link both rows and columns for each element in the
The SparseIntMatrix class should have all of the following methods:
● SparseIntMatrix(int numRows, int numCols) (constructor); Input: integers with the
number of rows and number of columns in this matrix; output: instance of this class
● SparseIntMatrix(int numRows, int numCols, String inputFile) (constructor); Input:
integers with the number of rows and number of columns in this matrix, and a String with
the filename of a file with matrix data. The format of the input file should be comma-
delimited lines with the row,column,data of each element. This constructor should
populate the matrix with this data; output: instance of this class
● int getElement(int row, int col); input: integers with the row and column of the desired
element; output: corresponding element (integer) if one exists or zero otherwise.
● boolean setElement(int row, int col, int data); input: integers with the row and column of
the element to be set and an integer with the matrix data; output: boolean indicating if
operation was successful (e.g. row/col were in the correct range)
● boolean removeElement(int row, int col, int data); input: integers with the row and
column of the element to be removed; output: boolean indicating if an element was
removed or not (false indicates that the element didn’t previously exist or that the row/col
were out of range, true indicates that it did and has been removed). Any links to/from the
element that was removed should be properly updated in the matrix.
● int getNumCols(); input: none; output: integer with the number of columns in this matrix.
● int getNumRows(); input: none; output: integer with the number of rows in this matrix
● boolean plus(SparseIntMatrix otherMat); input: another sparse matrix to be added to the
current one. This method should update the state of the current object; output: boolean
indicating if addition was successful (matrices should be identical dimensions)
● boolean minus(SparseIntMatrix otherMat); input: another sparse matrix to be subtracted
from the current one. This method should update the state of the current object; output:
boolean indicating if addition was successful (matrices should be identical dimensions)
Data members: any that are necessary to implement the methods above using the linked
list structure shown in Figure A. All data members should be declared private.
Part IV. (10 points) Testing your SparseIntMatrix Implementation
Now that you’ve finished implementing the SparseIntMatrix class, write a main method in a
separate class to test its functionality. We have provided three data files for you to test your
implementation: matrix1_data.txt, matrix2_data.txt, and matrix2_noise.txt. All three of these
files are comma-delimited with the following format on each line:
We have also provided a helper class MatrixViewer and EasyBufferedImage which will allow
you to visualize the patterns in these matrices. If you have implemented your matrix
construction correctly matrix1_data.txt will contain an obvious pattern, which you can view by
putting the following code inside a main method:
SparseIntMatrix mat = new SparseIntMatrix(800,800,”matrix1_data.txt”);
Matrix2_data.txt also contains a pattern, but it is obscured by random noise. All you’ll need to
do is load in the matrix in matrix2_noise.txt and subtract this matrix off of matrix2_data (i.e.
matrix2_data.minus(matrix2_noise). Check for a pattern before and after removing the noise—
if you’ve implemented your matrix arithmetic correctly, the pattern should be obvious. Be sure
to save all of the code that you use to check these patterns in your main method. To receive the
full 10 points for this section, you must successfully load and properly use all three example files
Part V. (10 points) Analysis and Comparison of Space Efficiency of your SparseIntMatrix
Answer the following questions about the memory used by your SparseIntMatrix implementation
relative to a standard 2-dimensional integer array. Please include your answers in the header of
your SparseIntMatrix.java file.
Assume that for the MatrixEntry class, each of the following require 1 memory unit: row label,
column label, matrix element data, link to next row element, link to next column element. Ignore
the overhead of the array that stores the links to the row/column linked lists— only consider the
memory used in storing matrix elements. Also, you can assume that each element of a 2D
array will require 1 memory unit. Be sure to justify how you arrived at your answers to receive
(a) For a square matrix of N x N elements with m non-zero elements, how much memory is
required for the SparseIntMatrix implementation? How much for a standard 2D array
(b) For a square matrix, assume N=100,000 and m=1,000,000. Is the SparseIntMatrix
implementation more space-efficient, and if so, by how much? (i.e. was it worth all of the effort
you just went through implementing it?) For what value of m does the 2D array implementation
become more space-efficient than the SparseIntMatrix implementation?
Submitting your finished assignment:
Once you’ve completed Project #3, create a zip file with all of your Java files (.java) and submit
them through Moodle.
Working with a partner:
As discussed in lecture, you may work with one partner to complete this assignment (max team
size = 2). If you choose to work as a team, please only turn in one copy of your assignment. At
the top of your class definition that implements your main program, include in the comments
both of your names and student IDs. In doing so, you are attesting to the fact that both of you
have contributed substantially to completion of the project and that both of you understand all
code that has been implemented.