I have implemented the DFA minimization algorithm with array lists, but it doesn't return the correct answer. If someone could point out which part of the algorithm I am missing, I would appreciate it.(And correction on whether I have used an efficient way to implement it).
The program is supposed to read data from a file and then work on it. But this function has nothing to do with those data. I have hard coded it to work.
The method that implements the algorithm is named (unreachableStates)
DEBUG I: So I went thorough the code, and found out that the problem is the loop that surround the expression | temp.add(transitionTable[j][i]) |. This will work for the first 2 iterations, but after that it will not consider all the states. Now the challenge is to fix it.
package dRegAut;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
public class dfamin {
// Global variables to hold data from the file
private int numStates,numAlphabets,numFinalStates;
private char alphabets[];
private boolean finalStates[];
private int [][] transitionTable;
/**
* #param args
* #throws IOException
* #throws Numberfor matException
*/
public static void main(String[] args) throws Numberfor matException, IOException {
int numStates,numAlphabets,numFinalStates;
char alphabets[];
boolean finalStates[];
int [][] transitionTable;
// Take file name and open a stream to read it
FileInputStream fileStream = new FileInputStream("/path/to/file/trace");
BufferedReader br = new BufferedReader(new InputStreamReader(fileStream));
// Store each line from the file
String line;
// Read each line from file
while((line = br.readLine()) != null){
// Read single spaced data from each line
String [] splittedLine = line.split(" ");
// Read numStates,numAlphabets from the line
numStates = Integer.parseInt(splittedLine[0]);
numAlphabets = Integer.parseInt(splittedLine[1]);
//for (int a=0;a<numAlphabets;a++){
//alphabets[a] = '0';
//}
transitionTable = new int[numStates][numAlphabets];
int tt= 2;
// Loop thorough the line and read transition table
for (int row=0;row<numStates;row++){
for (int col=0;col<numAlphabets;col++){
transitionTable[row][col] = Integer.parseInt(splittedLine[tt]);
tt++;
} // End of for -loop to go thorough alphabets
} // End of for -loop to go thorough states
// Read number of final states
numFinalStates = Integer.parseInt(splittedLine[2+numStates*numAlphabets]);
//System.out.println(numFinalStates);
// Read final states
int z=0;
finalStates = new boolean[numStates];
int start = 3+numStates*numAlphabets ;
int end = (3+(numStates*numAlphabets))+numFinalStates;
for (int fs=start;fs<end;fs++){
finalStates[ Integer.parseInt(splittedLine[fs])] = true;
//System.out.println(finalStates[z]);
z++;
} // End of for -loop to read all final states
dfamin x = new dfamin(numStates,numAlphabets,numFinalStates,finalStates,transitionTable);
//x.minimizer();
//System.out.println(x);
//System.out.println("======================");
int [][] ttt = {{1,2},{0,2},{1,0},{1,2}};
x.unreachableStates(4,2,ttt);
} // End of while-loop to read file
// Close the stream
br.close();
}
dfamin(int nS,int nA,int nFS,boolean fS[], int [][] tT){
numStates = nS;
numAlphabets = nA;
numFinalStates = nFS;
//alphabets = a;
finalStates = fS;
transitionTable = tT;
} // End of DFAMinimizer constructor
/*
* A method to minmize the dfa
*/
public void minimizer(){
} // End of minimizer method
/*
* A method to find unreachable states
*
*/
public void unreachableStates(int numStates, int numAlphabets, int [][] transitionTable){
// Initialize a list to hold temporary list of states in it
ArrayList<Integer> reachableStates =new ArrayList();
ArrayList<Integer> newStates = new ArrayList();
// Start from the state zero
reachableStates.add(0);
newStates.add(0);
// Temporary array to hold reachable states
ArrayList<Integer> temp = new ArrayList();
// Loop until there is data in newStates
do {
// Empty temp array
temp.clear();
for (int j=0;j<newStates.size();j++){
for (int i=0; i<numAlphabets;i++){
//System.out.printf("Alphabets:%d State:%ds ",i,j);
//System.out.printf("State:%d newStates:%d \n",j, newStates.get(j));
//System.out.printf("transitionTable: %d\n",transitionTable[j][i]);
temp.add(transitionTable[j][i]);
//System.out.printf("Temp[%d] = %d",i,temp.get(i));
//System.out.printf("Alphabets: %d", i);
} // End of for -loop to go thorough all characters
//System.out.printf("newStates: %d\n",newStates.get(j));
} // End of for -loop to go thorough all elements of the newStates array list
//System.out.printf("newStateSize: %d",newStates.size());
// Clear newStates list
newStates.clear();
//System.out.printf("Temp Size: %d", temp.size());
// Add the elements that are in temp, but are not in reachableStates to newStates
for (int z=0;z<temp.size();z++){
for (int z1=0; z1<reachableStates.size();z1++){
// if the state was already present, don't add
if (temp.get(z) == reachableStates.get(z1)){
break;
}
if (temp.get(z) != reachableStates.get(z1) && z1 == reachableStates.size()-1){
//System.out.printf("Temp:%d reachableStates:%d z:%d z1:%d \n",temp.get(z),reachableStates.get(z1),z,z1);
newStates.add(temp.get(z));
}
//System.out.printf("ReachableStates: %d ", reachableStates.get(z1));
} // End of for -loop to go thorough all reachableStates elements and check if a match
} // End of for -loop thorugh all temp states
//System.out.printf("NewStates Size after loop:%d \n",newStates.size());
if (!newStates.isEmpty()){
// Add the newStates elements to reachable states
for (int y=0;y<newStates.size();y++){
//System.out.printf("newStates:%d newStatesSize:%d in %d",newStates.get(y),newStates.size(),y);
reachableStates.add(newStates.get(y));
}
}
/*
//System.out.println();
System.out.printf("reachable states:");
for (int y=0;y<reachableStates.size();y++){
System.out.printf("%d",reachableStates.get(y));
}
System.out.printf("End!\n");
*/
} while(!newStates.isEmpty());
System.out.printf("Reachable sadfStates: ");
for (int w = 0;w<reachableStates.size()-1;w++){
System.out.printf(" %d ",reachableStates.get(w));
}
System.out.println();
} // End of unreachableStates method
}
After an hour of debugging, got it working. I just had to change the problem that I mentioned in DEBUG I (in question). I changed it as following:
transitionTable[newStates.get(j)][i]
Related
Hey everyone so I'm new to programming and recently I've been introduced to array's I've been having some problems in my current project. Essentially I am getting an array out of bounds exception when trying to calculate the discount price (afterDiscount located at the bottom) however when I run the program I get this error. I'm not sure how to fix it as I have not dealt with arrays before.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 9
at StarterJ52PartPriceDiscount.main(StarterJ52PartPriceDiscount.java:108)
import java.io.*;
import java.util.*;
public class StarterJ52PartPriceDiscount
{
public static void main(String[] args) throws FileNotFoundException
{
// Constants
final int MAX = 30; // max records on parts.dat
final int SENTINEL = 999;
// File Objects - Parts and Trans files
Scanner inPartsFile = new Scanner(new FileReader("parts.dat"));
Scanner inTransFile = new Scanner(new FileReader("trans.dat"));
// Part file Variables
int stkPartNo;
double stkPartPrice; // ???
// Tx file Variables
int txPartNo;
int txQuantity;
int txDiscountCode;
// Arrays
int[] partNos = new int[MAX];
double[] prices = new double[MAX];
int[] discounts = {0,5,10,15,20,25,30,40,50}; // Discount Percentages
// Other Variables
Scanner console = new Scanner(System.in);
int recCount; // no records on file
int cnt, foundPosition,i,pos; // index
double beforeDiscount, afterDiscount, totalDiscount, cost;
boolean found;
// Initialise
recCount = 0;
foundPosition = 0;
totalDiscount = 0;
found = false;
pos =-1;
// Output Part No and Prices (for)
System.out.println("Part No Part Price");
for(i=0; i <MAX; i++)
{
stkPartNo = inPartsFile.nextInt();
stkPartPrice = inPartsFile.nextDouble();
//System.out.printf("%2d %4.2f %n",stkPartNo,stkPartPrice );
partNos[i] = stkPartNo;
prices[i] = stkPartPrice;
System.out.printf("%6d %7.2f %n",partNos[i],prices[i]);
}//for
// Initial Tx read of first record
txPartNo=inTransFile.nextInt();
System.out.println("Part Quantity Disc Code");
while(txPartNo != SENTINEL)
{
txQuantity = inTransFile.nextInt();
txDiscountCode = inTransFile.nextInt();
System.out.printf("%4d %4d %4d %n",txPartNo,txQuantity,txDiscountCode );
txPartNo=inTransFile.nextInt();
}//While
// Verify Tx trans.dat contents (initially)
inTransFile.close();
inTransFile = new Scanner(new FileReader("trans.dat"));
System.out.println("xxxxxxx");
txPartNo=inTransFile.nextInt();//initial Read
while(txPartNo != SENTINEL)
{
txQuantity = inTransFile.nextInt();
txDiscountCode = inTransFile.nextInt();
System.out.printf("%4d %4d ",txPartNo,txQuantity );
found = false;
pos = -1;
while (pos < partNos.length -1 && found == false)
{
++pos;
if (partNos[pos] == txPartNo){
found = true;
}
else if (partNos[pos] > txPartNo){ // Ordered
pos = partNos.length; // break;
}
} // inner while
if (found) { // == true
beforeDiscount = prices[pos];
//Throws out of bounds exeption
afterDiscount = beforeDiscount - (beforeDiscount * discounts[txDiscountCode]);
System.out.printf("%4.2f %n",beforeDiscount);
System.out.printf("%4.2f %n",afterDiscount);
}
else {
System.out.println("NOT Found");
}//if
txPartNo=inTransFile.nextInt();//Sub Read
}//While
} // main
}
ThankYou for your comments I was able to rectify the problem, my discount array was beginning at position 1 rather than position 2, therefore, cause the out of bounds exception
changed the code from this
afterDiscount = beforeDiscount - (beforeDiscount * discounts[txDiscountCode]);
to this
afterDiscount = beforeDiscount - (beforeDiscount * discounts[txDiscountCode-1]);
This chapter of the course is teaching us about methods in Java, more specifically returning values. While the rubric called for it to just be able to apply values from a .txt list the 9 planets provided below the program. I wanted to go beyond and make it so that there would be no limit on the amount of celestial bodies this could apply to (as I did with the program that created the .txt as an output). I have a finished program by another student available to me. However, I'd rather try approaching it in another way(Though I must thank Omar because I had no idea you could return arrays from methods).
Currently, as is, the program compiles without any errors in BlueJ. However, It does not run, or even put out any test print statements I put in. It's been running for over an hour on core 2 of my overclocked i5, but nothing. Since the core is being stressed, I assume it's stuck in a loop somehow?
How may I solve this issue?
I really appreciate any advice, and hope to spend more time here in the future.
/**
* 7.04 This program will take gravity and textual data from a .txt
* and will perform calculations with it once I figure out how that may be done.
*
*
* #author ********
* #version (The Date)
*/
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class Weight2
{
// write static methods here
// Note: formula for finding weight on a planet: Earth weight divided by Gravity constant times surface gravity
public static String[] getData(int arraylength,int i, int value) {
String [] Gravityscan = new String[arraylength]; //Initiates String Arrays to be used
String [] pregravity = new String[arraylength];
String [] names = new String[arraylength];
String [] prevalues = new String[arraylength];
String [] error = {"error"};
String delims = "[ |\\ ]+"; // Sets Delimiters
File data2 = new File("Gravityoutput.txt"); //Opens data source
Scanner inFile = new Scanner("Gravityoutput.txt");
for(int m = 0; m < arraylength ; m++)
{
Gravityscan[m] = inFile.nextLine(); //String for each line being run
prevalues = Gravityscan[m].split(delims); //Split into two (gravity name)
pregravity[m] = prevalues[0]; //Sorts gravity string to array
names[m]= prevalues[1]; //Sorts name string to array
}
inFile.close();
//if (value == 0){return Integer.toString(arraylength);}
if (value == 1){return pregravity;} //Returns pregravity string for first part of loop below
else if (value == 2){return names;} //Returns names to end of for string below
else {System.out.print("AN ERROR HAS OCCURED IN METHOD GETDATA"); return error;}
}
//public static double calcWeight() {
//}
public static void main(String[] args)throws IOException
{
Scanner in = new Scanner(System.in);//Scanner activated
File data = new File("Gravityoutput.txt"); //Select file to get data from
Scanner inFile = new Scanner("Gravityoutput.txt");
int arraylength = 0; //Works with loop to determine length of data
while (inFile.hasNext())
{
arraylength++;
}
inFile.close(); //Closes file
System.out.print("arraylength is " + arraylength);//Beta testing check
double [] gravities = new double[arraylength]; //Declaring double array for after string conversion
//String[] names = new String[arraylength]; //Declaring array to be used for names
System.out.print("Please enter your mass on Earth in lbs: "); //User input for math
double earthWeight = in.nextDouble();
for(int i=0; i < arraylength; i++)
{
int value = 1;
String[] stringgravity = getData(arraylength, i, value);
gravities[i] = Double.parseDouble(stringgravity[i]);
System.out.print(gravities[i] + " gravity ");
value++;
String[] names = getData(arraylength, i, value);
System.out.println(names[i] + "gravity");
// static method you write Double.parseDouble
}
//double[] weight = calcWeight(earthWeight, gravity); // static method you write
//printResults(names, gravity, weight); // static method you write
} //end main
}//end class
//Below is the data contained by Gravityoutput.txt
3.70 Mercury
8.87 Venus
9.82 Earth
3.70 Mars
24.78 Jupiter
10.44 Saturn
8.86 Uranus
11.13 Neptune
0.61 Pluto
Creating an instance of Scanner with Scanner inFile = new Scanner("Gravityoutput.txt"); does not read input from the file, it reads input from the String "Gravityoutput.txt".
Try Scanner inFile = new Scanner(data); instead.
Oh, and your code is stuck in a loop :
inFile.hasNext() always returns true, since you never read anything from the Scanner.
You can replace it with
while (inFile.hasNext())
{
String str = inFile.next();
arraylength++;
}
Here is the program that I am trying to run:
/**
* Write a description of class mainGame here.
*
* #author Anthony Parsch
* #version 0.1.1
*/
//Import what I need to.
import java.io.*;
public class mainGame
{
/**
* Constructor for objects of class mainGame
*/
public static void main(String[] args)
{
// initialise instance variables
int xCoord = 10; //The map's max x coordinate +1
int yCoord = 10; //The map's max y coordinate +1
int playerX = 0; //The player's current x coordinate
int playerY = 0; //The player's current y coordinate
//Declare the arrays
String[][] map; //[x][y]The map
String[][] direc; //[x][y]Which directions that you can go
String[][] items; //[x][y]Where items are at
String[] inv; // Holds your inventory.
int[][] helpInt; //[x][y] All the other stuff in the
//Initalize the arrays
//---The player arrays
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
//---The map arrays
map = new String[xCoord][yCoord]; //Descriptions
direc = new String[xCoord][yCoord]; //north y++,west x--,south y--,east x++
items = new String[xCoord][yCoord]; //The items within the world
//Declare the values of map
map[0][0] = "You wake up with the feel of cold metal on your back. The only other thing in this room is the door.";
map[0][1] = "You are now in a hallway with a door behind you and one either side. Forward is a continuation of the hallway.com";
//Declare the values of direc
direc[0][0] = "north";
direc[0][1] = "north, south, east, west";
print(inv[0]); //Check that the functions work
print(findDirec(direc, 0, 0));
}
/**
* Finds and displays the avaliable exits for a coordinate.
*
* #param map[][] The map array from which this method pulls the directions from.
* #param x The x value of the map
* #param y The y value of the map
* #return The string value of which way you can go
*/
static String findDirec(String[][] map, int x, int y){
//Pulls the directions
String match = map[x][y];
//Checks Directions
boolean nor = match.matches("(.*)north(.*)");
boolean sou = match.matches("(.*)south(.*)");
boolean wes = match.matches("(.*)west(.*)");
boolean eas = match.matches("(.*)east(.*)");
//Displays directions
String placeHolder = "You can go ";
if (nor == true){
placeHolder = placeHolder + "north, ";
} else if(sou == true) {
placeHolder = placeHolder + "south, ";
} else if(wes == true) {
placeHolder = placeHolder + "west, ";
} else if(eas == true) {
placeHolder = placeHolder + "east";
}
//---Checks if east is in the string, if not it removes the space and comma
if (eas == false){
StringBuffer soo = new StringBuffer(placeHolder);
soo.delete((placeHolder.length()-3), (placeHolder.length()-1));
placeHolder = soo.toString();
}
//Adds the ending period
placeHolder = placeHolder + ".";
//Returns the string
return placeHolder;
}
//Adds an item to an inventory
static String[] addItem(String inv[], String item){
int i; //Counter for the for loop, and where to add the item at.
boolean stop = false;
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
inv[i] = item;
return inv;
}
static void print(String entry){
System.out.print(entry);
}
}
And when I try and run it through the Command Prompt, I get this error:
Exception in thread "main" java.lang.NullPointerExcpetion
at mainGame.addItem(mainGame.java:113)
at mainGame.main(mainGame.java:38)
When I paste this in to a text editor, line 113 is simply a closing brace }.
However, one line before that is a logic flaw which I presume is really line 113 for you.
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
Each iteration of the loop assigns true to stop and then tests if true equals true, which it does. Your condition to exit the loop is when true equals false, which is never the case, therefore your loop goes forever until an error occurs. Also, don't you want to iterate while stop is false? I think you have it backwards.
The next problem is your if statement, which is probably where your NullPointerException is coming from:
if(inv[i].equals("0"))
{
stop = true;
}
You assume that inv[i] refers to an object. You need a null check.
Three recommendations:
Never use = for a comparison. Use ==. Since this is a boolean, you can even simplify this to stop.
Check the length in your for loop.
Compare "0" to inv[i] instead of the other way around to avoid null pointer dereferencing.
Try this:
boolean stop = false;
for (int i = 0; i < inv.length && !stop; i++)
{
if("0".equals(inv[i])
{
stop = true;
}
}
Another option, and this is a matter of form, is to remove the looping variable and just break out of the loop explicitly.
for (int i = 0; i < inv.length; i++)
{
if("0".equals(inv[i])
{
break;
}
}
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
So you only initialize one index of your array but here:
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
.. you loop through all of them. just kidding, didn't read the full problem. You should still read the rest of my answer, but the reason why you get the NPE is because your loop condition is broken. (by the way your for loop condition is broken, it should test for equivalence using the == operator, not the assignment = operator.)
So what you actually are doing with that code is this :
inv = new String[10];
At this point you have a new String array of capacity 10, with no values inside, something like this:
[null][null][null][null][null][null][null][null][null][null]
inv[0] = "0";
Now you set [0] to "0", so:
["0"][null][null][null][null][null][null][null][null][null]
Then your loop attempts to access all of those null references, that'll probably be why you have a null reference exception.
To fix it, simply every index position in your array to anything that is not-null:
Arrays.fill(inv, "");
I use Arrays.fill() because it's shorter.
In your for loop condition, which one do you prefer?
stop = true or stop == true
for(i=0; i<inv.length && !stop; i++)
{
if(inv[i]!=null && inv[i].equals("0"))
{
stop = true;
}
}
I am continuing to get this error. Now I have gotten it for my SortSearchUtil. I've tried to do some debugging but can fix the issue. The error reads:
----jGRASP exec: java PostOffice
Exception in thread "main" java.lang.NullPointerException
at SortSearchUtil.selectionSort(SortSearchUtil.java:106)
at PostOffice.sortLetters(PostOffice.java:73)
at PostOffice.main(PostOffice.java:15)
----jGRASP wedge: exit code for process is 1.
----jGRASP: operation complete.
line 106 of selection Sort is:
if (array[indexSmallest].compareTo(array[curPos]) > 0)
I don't know what could be wrong with my method. It's a standard method that was given to me by my instructor. I've tried to debug my program but I'm pretty stuck. Here is the method that the error is originating from, selectionSort:
public static void selectionSort(Comparable[] array)
{
int curPos, indexSmallest, start;
Comparable temp;
for (start = 0; start < array.length - 1; start++)
{
indexSmallest = start;
for (curPos = start + 1; curPos < array.length; curPos++)
if (array[indexSmallest].compareTo(array[curPos]) > 0)
{
indexSmallest = curPos;
}
// end for
temp = array[start];
array[start] = array[indexSmallest];
array[indexSmallest] = temp;
} // end for
}
The sort method is at the bottom which calls SortSearchUtil.selectionSort of this Post Office Method:
import java.util.*;
import java.io.*;
public class PostOffice
{
private final int max = 1000;
private Letter [] ltrAra = new Letter[max];
private int count;
public static void main(String [] args)
{
PostOffice postOffice = new PostOffice();
postOffice.readLetters("letters.in");
postOffice.sortLetters();
postOffice.printLetters();
}
public PostOffice()
{
Letter [] Letters = ltrAra;
this.count = 0;
}
public void readLetters(String filename)
{
int count = 0;
int iWork = 0;
Scanner fin = new Scanner(filename);
String toName, toStreet, toCity, toState, toZip;
String fromName, fromStreet, fromCity, fromState, fromZip, temp;
double weight;
String sWork;
fin = FileUtil.openInputFile(filename);
if (fin != null)
{
while (fin.hasNext())
{
toName = fin.nextLine();
toStreet = fin.nextLine();
sWork = fin.nextLine();
iWork = sWork.indexOf(",");
toCity = sWork.substring(0, iWork);
iWork = iWork + 2;
toState = sWork.substring(iWork, iWork + 2);
iWork = iWork + 3;
toZip = sWork.substring(iWork);
fromName = fin.nextLine();
fromStreet = fin.nextLine();
sWork = fin.nextLine();
iWork = sWork.indexOf(",");
fromCity = sWork.substring(0, iWork);
iWork = iWork + 2;
fromState = sWork.substring(iWork, iWork + 2);
iWork = iWork + 3;
fromZip = sWork.substring(iWork);
sWork = fin.nextLine();
weight = Double.parseDouble(sWork);
ltrAra[count] = new Letter(toName, toStreet, toCity, toState, toZip, fromName, fromStreet, fromCity, fromState, fromZip, weight);
count++;
}
fin.close();
}
}
public void sortLetters()
{
SortSearchUtil.selectionSort(ltrAra);
}
public void printLetters()
{
for (Letter ltr : ltrAra)
{
System.out.println(ltr);
System.out.println();
}
}
}
My file looks like this "letters.in":
Stu Steiner
123 Slacker Lane
Slackerville, IL 09035
Tom Capaul
999 Computer Nerd Court
Dweebsville, NC 28804-1359
0.50
Tom Capaul
999 Computer Nerd Court
Dweebsville, NC 28804-1359
Chris Peters
123 Some St.
Anytown, CA 92111-0389
1.55
Obviously you get a NPE because:
You initialize ltrAra as array of 1000 items, but you read in less than 1000 items within method readLetters(). So at the end of this array some null references remain un-initialized (remember array-creation does itself not set the single items to any objects). Therefore following sorting-method gets some null-references => NPE.
Suggested solution:
You should use an ArrayList instead of an array because that will automatically prevent you from accessing too much items due to internal range check.
In addition to the above answer that Meno has well stated, you need to understand when you get a Null pointer Exception.
your error-line : if (array[indexSmallest].compareTo(array[curPos]) > 0)
If we get NPE in this line, it is obvious that array[indexSmallest] is null
And when you invoke an action on null, you get NPE. Hope this helps you to debug, down the line.
Also, One of the main reasons when we choose ArrayList over Arrays is when we do not know the length of the array.
One more suggestion, you can create an ArrayList and then convert to Arrays if you want to stick with Arrays
To convert ArrayList of any class into array, Convert T to the respective class. For eg: if you want String array, convert T to 'String'
List<T> list = new ArrayList<T>();
T [] students = list.toArray(new T[list.size()]);
................................
.XXXXXXXXXXXXXXX.....XXXXXXXXXX.
.X.....X.......X.....X........X.
.X.....X.......XXXXXXX........X.
.XXXXXXXXXXXX.................X.
.X....X.....X.................X.
.X....X.....XXXX..............X.
.XXXXXX........X..............X.
......X........X..............X.
......X........X..............X.
......X........X..............X.
......XXXXXXXXXXXXXXXXXXXXXXXXX.
................................
Looking for an algorithm to find the largest area. Here, "area" is defined as a number of dots (.) bounded by Xs.
private static void readFile(File inputFile) throws IOException {
Scanner fileScanner = new Scanner(inputFile);
Point previousPoint = null;
int rowCount = 0;
while(fileScanner.hasNext()){
String line = fileScanner.next();
String[] points = line.split(" ");
for(int columnCount=0;columnCount<points.length;columnCount++){
if(points[columnCount].equalsIgnoreCase("x")){
Point currentPoint = new Point();
currentPoint.setxValue(columnCount);
currentPoint.setyValue(rowCount);
}
}
rowCount++;
}
}
This is my first and struggling to move further.
This algorithm should work. You just need to implement it in Java.
Load the file into a char[][]. (1 char[] per line)
Loop through the char[][] (2 dimensionally)
upon finding a '.', perform flood fill, changing all '.' to ',', also incrementing a counter on every change.
At the end of flood fill, compare this counter with a globally set maximum. If it's higher, then set it as the new highest. (If the edges are not a proper boundary, then do not set this counter if you reached an edge during flood fill by setting a flag during 3)
Return the highest you set.
If you have any specific problems with the Java implementation, then let me know
Geobits:
Note: If you want to exclude the area "outside" any boxes, flood as
usual, but discard any area that hits the edge during the fill(skip
step 2.2 for that flood).
When doing the flood fill, you have 2 types of boundaries. A wall ('X'), and the edge of the array(which you need to explicitly check for to avoid OutOfBounds exceptions). If you hit an out of bounds, keep doing the fill, but set a flag so you know later to not consider the number you counted for the biggest box.
I was given this as assignment in an interview process and this is the compile and running code
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class FindArea {
public static void main(String[] args)
{
String fileName="C:\\map.txt";
FindArea area = new FindArea();
try{
FileReader inputFile = new FileReader(fileName);
BufferedReader bufferReader = new BufferedReader(inputFile);
char[][] twoArray= new char[100][100];
String line;
int i=0;
while ((line = bufferReader.readLine()) != null) {
twoArray[i] = line.toCharArray();
System.out.println(line);
i++;
}
bufferReader.close();
System.out.println("file read");
System.out.println("Max area: " + area.getMaxArea(twoArray));
} catch(Exception e) {
System.out.println("error : " + e.getMessage());
}
}
/**
* Get the maximum area from the given map
*
* #param charArray
* #return
*/
private int getMaxArea(char[][] charArray) {
HashMap<Integer, ArrayList<String>> numberOfBoxes = convertToBoxes(charArray);
numberOfBoxes = mergeOverlapAreas(numberOfBoxes);
int largeSize = 0;
for (Integer key : numberOfBoxes.keySet()) {
ArrayList<String> list = numberOfBoxes.get(key);
System.out.println("Key : " + key + " Size : " + list.size());
if (largeSize < list.size()) {
largeSize = list.size();
}
}
return largeSize;
}
/**
* Convert the 2d Array to HashMap
* Key being the count of boxes and
* Value being the list of indexes associations
*
* #param charArray
* #return
*/
private HashMap<Integer, ArrayList<String>> convertToBoxes(char[][] charArray) {
HashMap<Integer, ArrayList<String>> numberOfBoxes = new HashMap<Integer, ArrayList<String>>();
int boxes = 0;
for(int i=1; i<charArray.length; i++) {
for (int j=0; j<charArray[i].length; j++) {
if (charArray[i][j] == '.') {
boolean isExists = false;
for(Integer key : numberOfBoxes.keySet()) {
ArrayList<String> arrList = numberOfBoxes.get(key);
if(arrList != null) {
if(arrList.contains((i-1) + "-" + j) ||
arrList.contains(i + "-" + (j-1))) {
isExists = true;
arrList.add(i + "-" + j);
numberOfBoxes.put(key, arrList);
}
}
}
if (!isExists) {
ArrayList<String> list = new ArrayList<String>();
list.add(i + "-" + j);
numberOfBoxes.put(boxes, list);
boxes++;
}
}
}
}
return numberOfBoxes;
}
/**
* Check for the points exists in more than one area
* #param numberOfBoxes
* #return
*/
private HashMap<Integer, ArrayList<String>> mergeOverlapAreas( HashMap<Integer, ArrayList<String>> numberOfBoxes) {
for(Integer key : numberOfBoxes.keySet()) {
ArrayList<String> list1 = numberOfBoxes.get(key);
for (Integer key2 : numberOfBoxes.keySet()) {
if (key < key2) {
ArrayList<String> list2 = numberOfBoxes.get(key2);
Iterator<String> listIter = list2.iterator();
while(listIter.hasNext()) {
if (list1.contains(listIter.next())) {
list1.addAll(list2);
Set<String> noDuplicates = new HashSet<String>(list1);
numberOfBoxes.put(key, new ArrayList<String>(noDuplicates));
break;
}
}
}
}
}
return numberOfBoxes;
}
}
Here's an algorithm that's an alternative to flood fill. This method sweeps through the 2d array and whenever you encounter a node(pixel) that's outside to the left (right, top, bottom), it flags the current node as outside, ie if your neighbour is 'outside', you're marked 'outside' too.
The algorithm continues like this until there're no more updates. That means that all the nodes that are reachable from the 'outside' have been flagged. BTW, this is a very similar problem to level sets functions and updating them (where flood fill is also used). The nice this about this method is that it is ideal for parallelization.
1. Load 2D Symbol Array from File
2. hasupdates = false
3. Create 'isinside' bool array -> {
if(symbolarray[row][col] == '.' and row or col is at boundary)
isinside[row][col] = false
else
isinside[row][col] = true
}
4. do{
Do a sweep from left to right (for all rows) -> //This loop can be run parallely on all rows.
If (!isinside[row][col-1] and symbolarray[row][col] == '.'){
isinside[row][col] = false //mark current value as 'outside'
hasupdates = true
}
Do similar sweeps from right to left, top to bottom(all columns) and bottom to top.
}while(hasupdates)
5. Go through 'isinside' array and count the number of falses.
If you have huge files where you have to do this area calculation, you can have the sweeps along the rows and columns run parallely, because each row update (column update) is independent of the other updates.