In this lab you will work on a problem that shows up frequently in practice, for instance in Vision and Robotics: counting cells in a blob. This problem is a good illustration of the power of recursion.Its solution is relatively easy to write recursively but it would be much more difficult to write an iterative solution.
Have fun!!
For example:
(* denotes a filled cell) 4 * * 3 * * y 2 * * 1 * * 0 * * * 0 1 2 3 4 x For the above figure checkThisBlob called at x=1 y=3 should return a value of 5 checkThisBlob called at x=0 y=1 should return a value of 2 checkThisBlob called at x=4 y=4 should return a value of 0 checkThisBlob called at x=4 y=0 should return a value of 4
Your task in this lab is to write a recursive method checkThisBlob.
Algorithm
For any particular cell (x, y) there are three possibilities.
In the first two cases the size of the blob containing the cell(x, y) is zero because there is no blob. For the last case however further computations will be needed and so 1 and 2 are our base cases.
We must define the size of the blob containing the filled cell (x, y) in terms of the size of one or more smaller blobs. If we mark the filled cell (x, y) empty the moment we visit it then we can redefine the problem as follows:
if (the cell (x, y) is outside the grid) then the count is 0 else if (the cell (x, y) is EMPTY) then the count is 0 else if (the cell (x, y) is FILLED) then mark the cell (x, y) as EMPTY; the count is 1 + the counts of the cell (x, y)'s eight neighbours.
Notes
A side effect of the checkThisBlob routine is that all the elements of the blob containing the cell (x, y) are set to EMPTY. In other words the blob is erased.
If the cell visited is off the grid[][] or EMPTY, checkThisBlob returns a 0 immediately. Otherwise the recursive step executes.
checkThisBlob calls itself eight times, each time a different neighbour of the current cell is visited. The cells are visited in a clockwise manner starting with the neighbour above and to the left.
Common Errors
The sequence of statements executed in the routine checkThisBlob is very important.
The routine checkThisBlob() tests whether the cell (x, y) is on the grid before testing if it is empty. If the order were reversed then the condition ( grid[x][y] == EMPTY ) would reference an out-of-range element whenever the cell (x, y) was off the grid.
The statement grid[x][y] = EMPTY is used to set up conditions that will help solve a smaller version of the same problem and consequently preceeds the recursive calls.
If this statement was not executed first, then cell (x, y) would be counted more than once since it is a neighbour of each of its eight neighbours. In fact a much worse problem would occur. When each neighbour of the cell (x, y) is visited, checkThisBlob() is called again with the coordinates of the cell (x, y) as arguments. Thus if the cell (x, y) were still FILLED the recursive step would be executed erroneously and an infinite sequence of calls would be generated.
Related Problems
A side effect of the checkThisBlob routine is that the blob is erased from the array grid[][].
2-dimensional arrays
For this problem you will use a new type, a 2D-array. This is a type that stores an array of arrays, essentially a matrix, or a grid.
//declares a 2D array of 3 rows and 5 columns. The rows and columns are //numbered starting at 0. int a [3][5];In the example above there will be three rows, numbered 0, 1 and 2; and 5 columns, numbered 0, 1, 2, 3 and 4.
To access an element in a 2D array you need to specify two indices: the row, and the column. For example, a[0][0] gives the element in the 0th row and 0th column; a[1][3] gives the element in the 1st row and 3rd column, and so on.
We can assign values to a 2D array by assigning values to each element in part, with a loop, or at initialization, as follows:
int a [3][5] = { {0, 2,3,7,8}, {4,7,1,2,3}, {6,1,1,3,5} };In the example above, a[0][0] = 0, a[0][1] = 2, a[0][2] = 3, a[0][3]=7, a[0][4]=8, a[1][0] = 4, a[2][0] = 6, a[2][4] = 5. It is easiest if you visualize a 2D array as a matrix, rather than row and column representing vertical and horizontal.
What to Do
A skeleton of the program is given here: BlobCheck.java. Take a look at it.
Your main program makes a copy of grid[][] and passes it, along with the parameters x and y, to checkThisBlob. blobSize should return the value computed by checkThisBlob as its own result. A call to checkThisBlob will now not result in erasure of a blob on the original grid. This is the usual procedure to handle the aforementioned problem. Placing the copy operation at the beginning of our recursive routine would lead to the creation of a new grid on every recursive call - a totally unnecessary and very expensive waste of computing time and space. This is the single most crucial step in this lab!
Your program should simply output the values for each square in the grid.
The hardest part in this lab will be to debug your code. Feel free to use a different (smaller) grid to help with the process.
Send me only the .java files (not the entire folder), all in the same email, as attachments.