一、算法概述
1.泛洪算法(Flood Fill):图论和图像处理中的一种经典算法,用于确定连通区域。
它的典型应用是 "油漆桶"工具:点击图片中的一个像素,程序会把与该像素颜色相同且连通的区域全部填充为新颜色。
- 核心思想
从种子点(起点)出发,向四周相邻位置(通常四邻域或八邻域)扩散,访问所有"连通"且"满足条件"的节点,直到所有连通区域都被访问。。
3.连通规则:
4 邻域:上、下、左、右
8 邻域:上、下、左、右 + 对角线方向
条件:通常颜色相同(或特征相似)
二、实现方法
图论模型建立
// 网格图的抽象表示
typedef struct {
int color; // 节点颜色
int visited; // 访问标记(可选)
} Node;
// 四连通邻接关系(隐式图,不需要显式存储边)
// 每个节点最多有4个邻居:上、下、左、右
const int dx4 = {-1, 1, 0, 0}; // 行方向偏移
const int dy4 = {0, 0, -1, 1}; // 列方向偏移
//递归DFS版本(最接近图论定义)
#include <stdio.h>
#include <stdlib.h>
// 四连通泛洪填充(递归DFS)
// 参数说明:
// image: 二维数组,存储颜色值
// rows, cols: 图像尺寸
// x, y: 当前坐标
// targetColor: 要填充的目标颜色
// newColor: 新颜色
void floodFillRecursive(int** image,
int rows, int cols,
int x, int y,
int targetColor,
int newColor)
{
// 1. 边界检查(防止越界)
if (x < 0 || x >= rows || y < 0 || y >= cols) {
return;
}
// 2. 颜色匹配检查(图论中的"节点值相等")
if (image[x][y] != targetColor) {
return;
}
// 3. 访问当前节点(染色)
image[x][y] = newColor;
// 4. 递归访问所有邻接节点(图论中的DFS遍历)
floodFillRecursive(image, rows, cols, x + 1, y, targetColor, newColor);
floodFillRecursive(image, rows, cols, x - 1, y, targetColor, newColor);
floodFillRecursive(image, rows, cols, x, y + 1, targetColor, newColor);
floodFillRecursive(image, rows, cols, x, y - 1, targetColor, newColor);
}
// 注意:递归版本在图像较大时(>1000x1000)可能导致栈溢出
测试程序
#include <stdio.h>
#include <stdlib.h>
// 创建动态二维数组
int** createImage(int rows, int cols) {
int** image = (int**)malloc(sizeof(int*) * rows);
for (int i = 0; i < rows; i++) {
imagei = (int*)malloc(sizeof(int) * cols);
}
return image;
}
// 释放内存
void freeImage(int** image, int rows) {
for (int i = 0; i < rows; i++) {
free(imagei);
}
free(image);
}
// 打印图像
void printImage(int** image, int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%2d ", imageij);
}
printf("\n");
}
printf("\n");
}
// 复制图像
int** copyImage(int** src, int rows, int cols) {
int** dst = createImage(rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
dstij = srcij;
}
}
return dst;
}
int main() {
// 创建测试图像(0表示空白,1-9表示不同颜色)
int rows = 8, cols = 8;
int** original = createImage(rows, cols);
// 初始化复杂图像(包含多个连通区域)
int init[8][8] = {
{1, 1, 1, 2, 2, 2, 3, 3},
{1, 0, 1, 2, 0, 2, 3, 3},
{1, 1, 1, 2, 2, 2, 3, 3},
{4, 4, 4, 5, 5, 5, 6, 6},
{4, 0, 4, 5, 0, 5, 6, 6},
{4, 4, 4, 5, 5, 5, 6, 6},
{7, 7, 7, 8, 8, 8, 9, 9},
{7, 0, 7, 8, 0, 8, 9, 9}
};
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
original[i][j] = init[i][j];
}
}
printf("=== 原始图像 ===\n");
printImage(original, rows, cols);
// 测试1:递归DFS填充左上角区域(颜色1 -> 99)
int** img1 = copyImage(original, rows, cols);
printf("=== 测试1:递归DFS从(0,0)填充颜色1->99 ===\n");
floodFillRecursive(img1, rows, cols, 0, 0, 1, 99);
printImage(img1, rows, cols);
freeImage(img1, rows);
// 测试2:迭代DFS填充中间区域(颜色5 -> 55)
int** img2 = copyImage(original, rows, cols);
printf("=== 测试2:迭代DFS从(3,3)填充颜色5->55 ===\n");
floodFillIterativeDFS(img2, rows, cols, 3, 3, 5, 55);
printImage(img2, rows, cols);
freeImage(img2, rows);
freeImage(original, rows);
return 0;
}
三、经典应用场景
图像编辑器的油漆桶工具
游戏地图区域填充(扫雷翻开一片空白区)
迷宫/连通区域计数
多边形种子填充(计算机图形学)