• Tidak ada hasil yang ditemukan

Counting Organisms

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 157-161)

Recursion

5.8 Counting Organisms

for (j = 0; j < hi-lo+1; j++) A[lo + j] = T[j];

} //end merge

} //end class MergeSortTest

When run, the program produces the following output:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

In passing, we note that merge sort is a much faster sorting method than either selection sort or insertion sort.

Presumably, we will need a variable that keeps count of the number of organisms. Let’s call it orgCount. When a 1 is encountered for the first time, we will change it to orgCount + 1. Thus, the cells of organism 1 will be labeled 2, the cells of organism 2 will be labeled 3, and so on.

This is necessary since, if we start labeling from 1, we would not be able to distinguish between a 1 representing a not-yet-met cell and a 1 indicating a cell belonging to organism 1.

This “adding 1 to the label” is necessary only while we are processing the grid. When we print it, we will subtract 1 from the label so that, on output, organism 1 will be labeled 1, organism 2 will be labeled 2, and so on.

In writing the program, we assume that the grid data is stored in an array G and consists of m rows and n columns.

We will use MaxRow and MaxCol to denote maximum values for m and n, respectively. Data for the program consists of values for m and n, followed by the cell data in row order. For example, data for the previous grid will be supplied as follows:

5 7

0 1 0 1 1 1 0 0 0 1 1 0 0 0 1 1 0 1 0 0 1 1 0 1 0 0 1 1 1 1 0 0 0 1 0

We assume that the data will be read from a file, orgs.in, and output will be sent to the file orgs.out.

The gist of the program logic is as follows:

scan the grid from left to right, top to bottom when we meet a 1, we have a new organism add 1 to orgCount

call a function findOrg to mark all the cells of the organism

The function findOrg will implement the four possibilities outlined earlier. When it sees a 1 in grid position (i, j), say, it will call itself recursively for each of the grid positions to the north, east, south, and west of (i, j). All the details are shown in Program P5.2.

Program P5.2

import java.io.*;

import java.util.*;

public class Organisms { static int orgCount = 0;

public static void main(String[] args) throws IOException { Scanner in = new Scanner(new FileReader("orgs.in"));

PrintWriter out = new PrintWriter(new FileWriter("orgs.out"));

int m = in.nextInt(), n = in.nextInt();

int[][] G = new int[m][n];

for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) G[i][j] = in.nextInt();

for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (G[i][j] == 1) { orgCount++;

findOrg(G, i, j, m, n);

}

printOrg(out, G, m, n);

in.close(); out.close();

} // end main

public static void findOrg(int[][] G, int i, int j, int m, int n) { if (i < 0 || i >= m || j < 0 || j >= n) return; //outside of grid if (G[i][j] == 0 || G[i][j] > 1) return; //no cell or cell already seen // else G[i][j] = 1;

G[i][j]= orgCount + 1; //so that this 1 is not considered again findOrg(G, i - 1, j, m, n); //North

findOrg(G, i, j + 1, m, n); //East findOrg(G, i + 1, j, m, n); //South findOrg(G, i, j - 1, m, n); //West } //end findOrg

public static void printOrg(PrintWriter out, int[][] G, int m, int n) { out.printf("\nNumber of organisms = %d\n", orgCount);

out.printf("\nPosition of organisms are shown below\n\n");

for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++)

if (G[i][j] > 1) out.printf("%2d ", G[i][j] - 1);

//organism labels are one more than they should be else out.printf("%2d ", G[i][j]);

out.printf("\n");

}

} //end printOrg } //end class Organisms

If the file orgs.in contains the following:

5 7

0 1 0 1 1 1 0 0 0 1 1 0 0 0 1 1 0 1 0 0 1 1 0 1 0 0 1 1 1 1 0 0 0 1 0

then Program P5.2 produces the following output in the file orgs.out:

Number of organisms = 5

Position of organisms are shown below 0 1 0 2 2 2 0

0 0 2 2 0 0 0 3 3 0 2 0 0 4 3 0 5 0 0 4 4 3 3 0 0 0 4 0

Consider how findOrg identifies organism 1. In main, when i = 0 and j = 1, G[0][1] is 1, so the call findOrg(G, 0, 1, ...) will be made with G as follows:

0 1 0 1 1 1 0 0 0 1 1 0 0 0 1 1 0 1 0 0 1 1 0 1 0 0 1 1 1 1 0 0 0 1 0

In findOrg, since G[0][1] is 1, it will be set to 2, and the four calls to findOrg will be made as follows:

findOrg(G, -1, 1, ...); //immediate return since i < 0 findOrg(G, 0, 2, ...); //immediate return since G[0][2] is 0 findOrg(G, 1, 1, ...); //immediate return since G[1][1] is 0 findOrg(G, 0, -1, ...); //immediate return since j < 0

All of these calls return immediately, so only G[0][1] is marked with a 2.

Next, consider how findOrg identifies organism 3. In main, when i = 2 and j = 0, G[2][0] is 1, so the call findOrg(G, 2, 0, ...) will be made with G as follows (organism 2 would already have been labeled with 3):

0 2 0 3 3 3 0 0 0 3 3 0 0 0 1 1 0 3 0 0 1 1 0 1 0 0 1 1 1 1 0 0 0 1 0

(Remember that, during this phase, the label of an organism is 1 more than the number of the organism.) For this example, we will use the notation N, E, S and W (rather than subscripts) to indicate a grid position to the north, east, south, and west, respectively. At this stage, orgCount is 3 so that the cells will be labeled with 4.

The following are the calls generated to findOrg from the initial findOrg(2, 0, ...) (for clarity, we omit the first argument, G):

findOrg(2, 0, ...) //G[2][0] is labeled with 4

findOrg(N...) //returns immediately since G[N] is 0

findOrg(E...) //G[E] is 1, relabeled with 4, gives rise to 4 calls findOrg(N...) //returns immediately since G[N] is 0

findOrg(E...) //returns immediately since G[E] is 0 findOrg(S...) //returns immediately since G[S] is 0 findOrg(W...) //returns immediately since G[W] is 4

findOrg(S...) //G[S] is 1, relabeled with 4, gives rise to 4 calls findOrg(N...) //returns immediately since G[N] is 4

findOrg(E...) //returns immediately since G[E] is 0

findOrg(S...) //G[S] is 1, relabeled with 4, gives rise to 4 calls findOrg(N...) //returns immediately since G[N] is 4

findOrg(E...) //G[E] is 1, relabeled with 4, gives rise to 4 calls findOrg(N...) //returns immediately since G[N] is 0

findOrg(E...) //returns immediately since G[E] is 0

findOrg(S...) //returns immediately since G[S] is outside grid findOrg(W...) //returns immediately since G[W] is 4

findOrg(S...) //returns immediately since G[S] is outside grid

findOrg(W...) //returns immediately since G[W] is outside grid findOrg(W...) //returns immediately since G[W] is outside grid findOrg(W...) //returns immediately since G[W] is outside grid

When the call findOrg(2, 0, ...) finally returns, G would be changed to this:

0 2 0 3 3 3 0 0 0 3 3 0 0 0 4 4 0 3 0 0 1 4 0 1 0 0 1 1 4 4 0 0 0 1 0

The third organism (labeled 4) has been identified. Note that each cell in the organism gave rise to four calls to findOrg.

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 157-161)