Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flood Fill Optimization: Attempting to Using a Queue

I am trying to create a filling method which takes the initial coordinate specified by the user, checks the character and then changes it as desired. After doing so, it then checks adjacent squares and repeats the process. After some research, I came across the flood fill algorithm and after trying that (it works but cannot meet my maximum requirement of an array of 250 by 250 characters).

My original flood fill algorithm was as follows:

public static void fillArea (int x, int y, char original, char fill){

   if (picture[y-1][x-1] != original){
      return;
   }
   picture[y-1][x-1] = fill;
   fillArea (x-1, y, original, fill);
   fillArea (x+1, y, original, fill);
   fillArea (x, y-1, original, fill);
   fillArea (x, y+1, original, fill);

   return;
}

After testing, I began to try the Queue method as explained on Wikipedia and this question asked previously regarding a similar issue. So far, I have come up with the following code:

public static void fillArea (int x, int y, char original, char fill){
  if (x != 0)
     x--;
  if (y!= 0)
     y--;
  Queue<Point> queue = new LinkedList<Point>();
  if (picture[y][x] != original){
      return;
  }
  queue.add(new Point(x, y));

  while (!queue.isEmpty()){
      Point p = queue.remove();
      if (picture[p.y][p.x] == original){
         picture[p.y][p.x] = fill;
         queue.add(new Point(p.x-1, p.y));
         queue.add(new Point(p.x+1, p.y));
         queue.add(new Point(p.x, p.y-1));
         queue.add(new Point(p.x, p.y+1));
      }
   }

   return;
}

While the first, recursive method was able to work for smaller values, it does not work when the array gets too large. However, the second method is taking me into some sort of infinite loop that I am unable to identify due to my inexperience with Queues. How can I either optimize the first code sample to work with larger samples or fix the second so that it gives results? Can anyone explain how to code any of these two or what I am doing wrong?

Thanks!

EDIT: I was able to find the infinite loop error in the second code (it has been fixed) but the queue based method does not fill the complete area. In fact, it fills less of an area than the recursion-based method. EDIT 2: It now works for square arrays. How can I ensure that it works for rectangular arrays as well (the second method).

like image 975
n0shadow Avatar asked Nov 03 '22 15:11

n0shadow


2 Answers

Shouldn't

if (picture[p.y][p.x] == original){
     picture[p.y-1][p.x-1] = fill;

be

if (picture[p.y][p.x] == original){
     picture[p.y][p.x] = fill;

in the Queue - approach?

like image 81
Fildor Avatar answered Nov 09 '22 08:11

Fildor


For reference, the question was fixed by added a buffer border around the array that it was handling. For example, if the array to be filled was

000
000
000

it was made into

   #####
   #000#
   #000#
   #000#
   #####

before being handled.

like image 45
n0shadow Avatar answered Nov 09 '22 07:11

n0shadow