package com.thealgorithms.others;
import java.util.LinkedList;
import java.util.Queue;
/**
* Implementation of the Flood Fill algorithm using an iterative BFS (Breadth-First Search) approach.
*
*
The Flood Fill algorithm is used to fill connected areas in an image with a new color, starting from a specified point.
* This implementation uses an iterative BFS approach with a queue
* instead of recursion to avoid stack overflow issues with large images.
*
* Implementation Features:
*
* - Supports 8-connected filling (horizontal, vertical, and diagonal directions)
* - Uses BFS traversal through {@link java.util.Queue}
* - Includes nested {@code Point} class to represent pixel coordinates
* - Iterative approach avoids stack overflow for large images
*
*
* Time Complexity: O(M × N) where M and N are the dimensions of the image
* Space Complexity: O(M × N) in the worst case the queue stores every pixel
*
* @see Flood Fill Algorithm - GeeksforGeeks
* @see Flood Fill Algorithm - Wikipedia
*/
public final class IterativeFloodFill {
private IterativeFloodFill() {
}
/**
* Iteratively fill the 2D image with new color
*
* @param image The image to be filled
* @param x The x coordinate at which color is to be filled
* @param y The y coordinate at which color is to be filled
* @param newColor The new color which to be filled in the image
* @param oldColor The old color which is to be replaced in the image
* @see FloodFill BFS
*/
public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
if (image.length == 0 || image[0].length == 0 || newColor == oldColor || shouldSkipPixel(image, x, y, oldColor)) {
return;
}
Queue queue = new LinkedList<>();
queue.add(new Point(x, y));
int[] dx = {0, 0, -1, 1, 1, -1, 1, -1};
int[] dy = {-1, 1, 0, 0, -1, 1, 1, -1};
while (!queue.isEmpty()) {
Point currPoint = queue.poll();
if (shouldSkipPixel(image, currPoint.x, currPoint.y, oldColor)) {
continue;
}
image[currPoint.x][currPoint.y] = newColor;
for (int i = 0; i < 8; i++) {
int curX = currPoint.x + dx[i];
int curY = currPoint.y + dy[i];
if (!shouldSkipPixel(image, curX, curY, oldColor)) {
queue.add(new Point(curX, curY));
}
}
}
}
/**
* Represents a point in 2D space with integer coordinates.
*/
private static class Point {
final int x;
final int y;
Point(final int x, final int y) {
this.x = x;
this.y = y;
}
}
/**
* Checks if a pixel should be skipped during flood fill operation.
*
* @param image The image to get boundaries
* @param x The x coordinate of pixel to check
* @param y The y coordinate of pixel to check
* @param oldColor The old color which is to be replaced in the image
* @return {@code true} if pixel should be skipped, else {@code false}
*/
private static boolean shouldSkipPixel(final int[][] image, final int x, final int y, final int oldColor) {
if (x < 0 || x >= image.length || y < 0 || y >= image[0].length || image[x][y] != oldColor) {
return true;
}
return false;
}
}