The short answer

Flood fill vs boundary fill comes down to what each one checks. Boundary fill paints outward from a seed pixel until it hits a boundary colour. So it can fill a region whose interior has several different colours. Flood fill instead paints every pixel that matches one old interior colour. It needs a uniform interior, but it does not care what colour the border is. Both spread from a seed pixel. Both can leak, too: a gap in the boundary, or a stray patch of the old colour, breaks the assumption each one relies on. Neither is faster in general, since both visit each pixel in the region once.

Paint a closed shape on screen, and something still has to decide which pixels inside it change colour. That job belongs to a seed fill algorithm. Computer graphics gives you two classic ones to learn.

Flood fill and boundary fill look almost identical in pseudocode. Yet GATE papers and viva questions turn on one small difference between them. This guide walks through both, then runs the same 7 by 7 grid through each. You can see, pixel by pixel, where they part ways.

Filling sits downstream of the pipeline that draws a shape’s outline. A stack-based fill is depth-first, and a queue-based fill is breadth-first, an idea that returns later in this guide. See DFS vs BFS first if that distinction is new to you.

Two pixel grids side by side comparing boundary fill and flood fill from the same seed pixel, with boundary fill covering two odd squares that flood fill leaves unfilled
Same grid, same seed pixel, two different results: boundary fill covers every interior square, flood fill leaves the odd ones behind.

What Seed Fill Algorithms Do

Area filling starts from one known pixel inside a shape, called the seed. From there, the algorithm spreads outward, pixel by pixel. At each step, it decides whether to paint the next neighbour.

Both algorithms here are seed fill algorithms for that reason. Each begins at a seed. Each keeps visiting neighbours until no unpainted neighbour is left. The spreading itself, up, down, left, right, and sometimes diagonally, is identical between them.

What differs is the stopping rule. Boundary fill watches for a border colour. Flood fill instead watches for the colour it is replacing. That single change is the entire subject of this article, and the worked example below makes it concrete.

The Boundary Fill Algorithm

Boundary fill starts at a seed pixel and spreads outward. It stops only when it meets a specified boundary colour. Everything inside that border gets painted, no matter how many colours the interior already contains.

The condition is simple. If the current pixel’s colour is neither the boundary colour nor the fill colour, paint it, then recurse into its neighbours. The check only ever looks for the boundary colour. So a stray patch of a third colour inside the region gets painted over too. That is the algorithm’s defining strength, not a limitation.

Here is the pseudocode:

def boundary_fill(x, y, fill, boundary):
    if get_pixel(x, y) != boundary and get_pixel(x, y) != fill:
        set_pixel(x, y, fill)
        boundary_fill(x + 1, y, fill, boundary)
        boundary_fill(x - 1, y, fill, boundary)
        boundary_fill(x, y + 1, fill, boundary)
        boundary_fill(x, y - 1, fill, boundary)

The call takes four parameters: x, y, the fill colour, and the boundary colour. Notice that interior colour never appears in the call at all.

Advantages of boundary fill:

  • Handles a multi-coloured interior without any extra logic, since it never checks interior colour at all.
  • Works well for shapes built from several smaller regions merged visually into one outline.
  • Simple to state: paint until you hit the border.

Disadvantages of boundary fill:

  • Needs the region’s border drawn in one single uniform colour, or the stopping rule breaks.
  • Leaks outside the shape if the boundary has even a one-pixel gap.
  • The classic recursive version can overflow the call stack on a large region.

The Flood Fill Algorithm

Flood fill starts at a seed pixel too. Its stopping rule, though, looks the other way. It replaces every connected pixel that matches one old interior colour with the fill colour. It stops wherever that old colour stops.

The condition mirrors boundary fill’s. If the current pixel’s colour equals the old colour, paint it, then recurse into its neighbours. So flood fill needs the interior to be uniformly one colour before it starts. Any pixel of a different colour inside is left untouched, since it never matches the old colour being replaced.

Here is the pseudocode:

def flood_fill(x, y, fill, old):
    if get_pixel(x, y) == old:
        set_pixel(x, y, fill)
        flood_fill(x + 1, y, fill, old)
        flood_fill(x - 1, y, fill, old)
        flood_fill(x, y + 1, fill, old)
        flood_fill(x, y - 1, fill, old)

The call also takes four parameters: x, y, the fill colour, and the old colour. Flood fill never inspects the border. So the border may be several different colours at once, and the algorithm will not notice.

Advantages of flood fill:

  • Places no requirement on the boundary colour, so an outline drawn in mixed colours still works.
  • Matches exactly what a paint bucket tool in an image editor needs to do.
  • Simple to state: paint every pixel that still matches the old colour.

Disadvantages of flood fill:

  • Needs a uniform interior colour, so any patterned or shaded region confuses it.
  • An odd-coloured pixel inside the region survives the fill untouched, which is not always what you want.
  • The classic recursive version, like boundary fill’s, can overflow the call stack on a large region.

Flood Fill vs Boundary Fill: Comparison Table

Infographic comparing boundary fill and flood fill on what each stops at, what each needs, what each checks per pixel, and what each is used for
Flood fill vs boundary fill at a glance: stopping condition, requirement, per-pixel check, and typical use.
AspectBoundary FillFlood Fill
Stopping conditionReaches the specified boundary colourReaches a pixel that is not the old colour
Per-pixel checkColour is not the boundary and not the fill colourColour equals the old colour
What defines the regionThe border colour, drawn around the shapeThe interior colour, filled inside the shape
Interior colour requirementNone; the interior may hold several coloursMust be uniformly one colour throughout
Boundary colour requirementMust be one uniform colourNone; the border may be several colours
Parameters passedx, y, fill colour, boundary colourx, y, fill colour, old colour
Behaviour toward an odd-coloured interior pixelPaints over it, since it is not the boundary colourLeaves it untouched, since it is not the old colour
How it fails or leaksLeaks out through any gap in the boundaryLeaks wherever the old colour continues outside the shape; under-fills if an off-colour patch splits the region
Connectivity variants4-connected or 8-connected4-connected or 8-connected
Recursion depth and memoryOne call per pixel; risks stack overflow on large regionsOne call per pixel; risks stack overflow on large regions
Suitability for patterned or shaded interiorsWell suited, since interior colour is never checkedPoorly suited, since it expects one uniform colour
Seed pixel outside the regionFills the surrounding area instead, up to the nearest boundary colourFills whatever region shares the seed’s own colour
Typical use caseShapes assembled from several merged sub-regionsAn image editor’s paint bucket tool
Time complexityO(n) in the number of pixels in the filled areaO(n) in the number of pixels in the filled area

Worked Example: The Same Seed, Two Results

Take this 7 by 7 grid. The # marks the boundary colour. The . marks the interior colour. Two stray o pixels sit inside the region in a third colour. The seed is at column 3, row 3, right in the centre.

#######
#.....#
#..o..#
#.....#
#..o..#
#.....#
#######

Run boundary fill from the seed with fill colour * and boundary colour #. The check only looks for #. So both o pixels get painted along with everything else:

#######
#*****#
#*****#
#*****#
#*****#
#*****#
#######

Run flood fill from the same seed with fill colour * and old colour .. This time the check looks for .. The o pixels never match, so they survive untouched:

#######
#*****#
#**o**#
#*****#
#**o**#
#*****#
#######

Same grid, same seed, same fill colour. Yet the two results differ by exactly two pixels. Boundary fill swallows the odd pixels, because it never checks interior colour. Flood fill leaves them behind, because they fail its one and only test. Keep this picture in mind. It explains almost every other row in the comparison table above.

4-Connected vs 8-Connected Filling

Diagram of a centre pixel with arrows to its four orthogonal neighbours labelled 4-connected beside the same pixel with arrows to all eight neighbours labelled 8-connected
4-connected visits four neighbours; 8-connected also visits the diagonals.

Both algorithms come in two connectivity variants. The choice is independent of which fill you use. A 4-connected fill visits up, down, left, and right. An 8-connected fill visits those four plus the four diagonals.

A 4-connected fill never moves diagonally. So it cannot pass through an opening that only touches at a corner. A thin diagonal sliver of the region can be left unfilled as a result. An 8-connected fill has no such gap, since it steps through corners too.

That extra reach cuts both ways, though. An 8-connected fill can leak through a diagonal gap that a 4-connected fill would have respected. Neither variant is universally better. The right choice depends on how the shape and its boundary were drawn.

Code Example

Below is a working Python version of both algorithms. Recursion is easy to write but risky on large regions. So both versions here use an explicit stack instead. That turns either one into an iterative, depth-first walk; see stack vs queue data structures for why a stack gives depth-first order, while a queue would give breadth-first order instead.

def boundary_fill(grid, x, y, fill, boundary):
    grid = [row[:] for row in grid]
    stack = [(x, y)]
    while stack:
        cx, cy = stack.pop()
        if grid[cy][cx] != boundary and grid[cy][cx] != fill:
            grid[cy][cx] = fill
            stack.extend([(cx + 1, cy), (cx - 1, cy),
                           (cx, cy + 1), (cx, cy - 1)])
    return grid


def flood_fill(grid, x, y, fill, old):
    grid = [row[:] for row in grid]
    stack = [(x, y)]
    while stack:
        cx, cy = stack.pop()
        if grid[cy][cx] == old:
            grid[cy][cx] = fill
            stack.extend([(cx + 1, cy), (cx - 1, cy),
                           (cx, cy + 1), (cx, cy - 1)])
    return grid


start = [
    list("#######"),
    list("#.....#"),
    list("#..o..#"),
    list("#.....#"),
    list("#..o..#"),
    list("#.....#"),
    list("#######"),
]

bf = boundary_fill(start, 3, 3, "*", "#")
ff = flood_fill(start, 3, 3, "*", ".")

print("Boundary fill result:")
for row in bf:
    print("".join(row))

print("\nFlood fill result:")
for row in ff:
    print("".join(row))

# Boundary fill result:
# #######
# #*****#
# #*****#
# #*****#
# #*****#
# #*****#
# #######
#
# Flood fill result:
# #######
# #*****#
# #**o**#
# #*****#
# #**o**#
# #*****#
# #######

Run this, and the two grids match the worked example exactly. Notice that boundary_fill checks for boundary, while flood_fill checks for old. That one line is the entire difference between the two functions.

When to Use Which

Use boundary fill when the outline is drawn in one consistent colour, but the interior might already hold other colours, such as text, icons, or overlapping sub-shapes. It also suits shapes assembled from several regions merged under one visible border.

Use flood fill when the interior starts out uniformly coloured, and you simply want to swap that colour for another. That is exactly the paint bucket tool in an image editor. It is why flood fill, not boundary fill, sits behind that feature almost everywhere. Filling only matters once a shape sits correctly on screen; see geometric transformation vs coordinate transformation for how it gets there first.

If neither assumption holds cleanly, patterned interior and patchy boundary both, plan on extra logic beyond either textbook version.

Interview Questions

The condition that guards the recursive call. Boundary fill paints a pixel when its colour is neither the boundary colour nor the fill colour. Flood fill paints a pixel when its colour equals the old interior colour. Everything else, the spreading to neighbours, the seed start, the recursion, is identical between them.

Boundary fill’s check never looks at interior colour at all. It only asks whether a pixel is the boundary colour. So any pixel that is not the border gets painted, regardless of what colour it started as. Flood fill’s check is the opposite. It only paints a pixel that matches one specific old colour, so a different colour inside the region is simply skipped.

Each recursive call adds a new frame to the call stack. A large filled region can need thousands of nested calls before the recursion unwinds. Most runtimes cap call stack depth well below that. An iterative version, using an explicit stack, avoids the limit entirely, since it stores pending pixels on the heap instead.

It can leak through. An 8-connected fill steps diagonally as well as orthogonally. So a boundary that only touches at one corner does not stop it. A 4-connected fill, restricted to up, down, left, and right, would treat that same corner gap as closed and stay inside the region.

Frequently Asked Questions

No, it never looks at the boundary at all. Flood fill only checks whether a pixel matches the old interior colour it is replacing. It stops wherever that old colour stops, regardless of what colour, or colours, sit along the border.

Yes, and that is precisely what it is built for. Its check only tests for the boundary colour and the fill colour. So any other colour inside the region gets painted over too. A multi-coloured interior is not a problem for boundary fill. It is the case the algorithm handles best.

Neither is faster in general. Both visit each pixel in the filled region at most once, so both run in O(n) time for n pixels. Actual speed depends more on the region’s shape and the connectivity variant chosen. Which algorithm you pick matters less.

Flood fill. Clicking a paint bucket tool replaces every connected pixel of the colour you clicked with a new one, which is exactly flood fill’s job. Boundary fill would need a separate, explicitly drawn border colour to stop at. Ordinary images rarely have one.

The algorithm fills whatever connected region shares the seed pixel’s own colour, wherever that is. It has no concept of an intended shape, only a starting colour to match. So a seed placed outside the shape fills the surrounding area instead. If the seed sits on an isolated pixel, it repaints just that one pixel.

No, they can give different results on the same region. A 4-connected fill can leave a thin diagonal sliver unfilled where an 8-connected fill would reach it. An 8-connected fill, in turn, can leak through a corner gap that a 4-connected fill would have respected. Neither variant is the safe default in every case.

Wrapping Up

Flood fill and boundary fill both spread paint outward from a seed pixel. Their pseudocode differs by one condition. Boundary fill checks for the boundary colour, so it can cross a multi-coloured interior freely. Flood fill checks for the old interior colour instead, so it needs a uniform interior but never looks at the border at all.

Keep the worked grid in mind for your exam. The two stray pixels got painted under boundary fill and survived under flood fill. That single picture is the whole comparison in miniature. Both come in 4-connected and 8-connected variants. Both are O(n). An iterative stack keeps either one safe from a stack overflow on a large region.

Related reading on DiffStudy:


Whatsapp-color Created with Sketch.

By Arun Kumar

Full Stack Developer with a BE in Computer Science, working with React, Next.js, Node.js, MongoDB, and AI/ML tools. Founder of DiffStudy — built to help CS students ace GATE and university exams, and keep developers up to date across AI, cloud, system design, web development, and every field of computer science. Every article is written from real hands-on experience, not just theory.

Leave a Reply

Your email address will not be published. Required fields are marked *


You cannot copy content of this page