BFS算法篇——FloodFill问题的高效解决之道(上)

文章目录

  • 前言
  • 一. FloodFill 问题概述
  • 二. BFS 在 FloodFill 中的应用
  • 三. BFS FloodFill 算法的优势
  • 四. BFS FloodFill 的实现
  • 小结

前言

BFS(广度优先搜索,Breadth-First Search)是一种图搜索算法,主要用于遍历或搜索树或图的所有节点。BFS 从根节点开始,首先访问当前节点的所有邻居节点,然后按层次逐步向外扩展。该算法通常用于找出两点之间的最短路径、计算连通区域、解决迷宫问题等。

一. FloodFill 问题概述

FloodFill 是一种常见的图像处理算法,通常用于填充图形区域。例如,在绘图软件中,当用户点击某个区域时,FloodFill算法用于填充该区域,使得区域内的像素颜色被替换为新颜色。该算法类似于“洪水”蔓延到相邻的区域,因此得名“FloodFill”。

  • FloodFill 的目标是从起始点出发,遍历并改变与起始点具有相同特征的所有相邻区域的颜色。
  • 该算法通常使用递归或广度优先搜索(BFS)来完成区域的遍历和填充。

二. BFS 在 FloodFill 中的应用

在 FloodFill 算法中,BFS 可以用来处理从起始点开始,向外扩展的填充操作。
具体而言,BFS 可以通过以下步骤实现 FloodFill:

  • 初始化:选择起始位置(如图像中的某一像素)并设定目标颜色(即需要替换的颜色)。
  • 队列操作:将起始像素加入队列。

扩展过程:

从队列中取出一个像素,检查其邻居像素是否符合填充条件(通常是具有相同颜色的像素)。 如果符合条件,将该邻居像素添加到队列,并改变其颜色。
重复操作:继续从队列中取出像素并进行扩展,直到所有可填充的区域都被处理完毕。 通过 BFS遍历的方式,可以确保所有与起始像素相邻的区域都被填充,且不会遗漏任何部分。

三. BFS FloodFill 算法的优势

  • 避免栈溢出:传统的递归 FloodFill(深度优先搜索)可能会导致栈溢出,特别是当区域非常大时。使用 BFS 可以避免这个问题,因为 BFS 使用队列,而不是栈。
  • 层次遍历:BFS 按层次扩展,可以确保在填充过程中按照一定的顺序进行,避免重复填充已处理过的像素。

四. BFS FloodFill 的实现

以下是 BFS 实现 FloodFill 算法的简单示例:

在这个 C 语言实现中,我们将使用队列(queue)来实现广度优先搜索。这个算法用于在一个二维图像中填充与起始点颜色相同的相邻像素。

#include 
#include 

#define MAX_ROWS 100
#define MAX_COLS 100

// 定义一个队列结构
typedef struct {
    int x, y;
} Point;

typedef struct {
    Point points[MAX_ROWS * MAX_COLS];
    int front, rear;
} Queue;

void initQueue(Queue *q) {
    q->front = q->rear = 0;
}

int isEmpty(Queue *q) {
    return q->front == q->rear;
}

void enqueue(Queue *q, Point p) {
    q->points[q->rear++] = p;
}

Point dequeue(Queue *q) {
    return q->points[q->front++];
}

// 用于填充的函数,bfs_floodfill
void bfs_floodfill(int image[MAX_ROWS][MAX_COLS], int rows, int cols, Point start, int target_color, int new_color) {
    // 如果目标颜色和新颜色相同,则不做任何更改
    if (target_color == new_color) return;

    // 创建队列
    Queue q;
    initQueue(&q);

    // 将起始点加入队列
    enqueue(&q, start);
    image[start.x][start.y] = new_color;

    // 定义四个方向(上,下,左,右)
    int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    
    while (!isEmpty(&q)) {
        Point p = dequeue(&q);

        // 遍历当前点的四个邻居
        for (int i = 0; i < 4; i++) {
            int nx = p.x + directions[i][0];
            int ny = p.y + directions[i][1];

            // 检查邻居是否在图像范围内,且颜色是否为目标颜色
            if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && image[nx][ny] == target_color) {
                // 填充该邻居的颜色
                image[nx][ny] = new_color;
                // 将该邻居加入队列
                enqueue(&q, (Point){nx, ny});
            }
        }
    }
}

// 辅助函数:打印图像
void printImage(int image[MAX_ROWS][MAX_COLS], int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", image[i][j]);
        }
        printf("\n");
    }
}

int main() {
    // 初始化一个图像(矩阵)
    int image[MAX_ROWS][MAX_COLS] = {
        {1, 1, 1, 0, 0},
        {1, 1, 0, 0, 0},
        {1, 1, 0, 0, 0},
        {0, 0, 0, 2, 2},
        {0, 0, 0, 2, 2}
    };

    // 图像大小
    int rows = 5, cols = 5;
    // 定义起始点
    Point start = {0, 0};
    // 原始颜色与目标颜色
    int target_color = 1;
    int new_color = 3;

    printf("Before FloodFill:\n");
    printImage(image, rows, cols);

    // 执行 BFS FloodFill
    bfs_floodfill(image, rows, cols, start, target_color, new_color);

    printf("\nAfter FloodFill:\n");
    printImage(image, rows, cols);

    return 0;
}

代码解析
队列实现:

  • 我们定义了一个 Queue 结构体,其中包含了一个 Point 数组来存储队列元素(即每个像素的坐标),以及两个指针 front 和 rear 来指示队列的前端和后端。
  • initQueue() 初始化队列,isEmpty() 检查队列是否为空,enqueue() 向队列添加元素,dequeue() 从队列中取出元素。

FloodFill 实现:

  • bfs_floodfill() 函数实现了 BFS 算法。在这个函数中,首先判断目标颜色和新颜色是否相同,如果相同就不做任何更改。
  • 然后将起始点加入队列,并开始广度优先搜索。对于每个像素,检查其四个方向的邻居(上下左右),如果邻居像素的颜色是目标颜色,就将其颜色改为新颜色,并将其加入队列。
  • 直到队列为空,所有可以填充的区域都被处理完。

辅助函数:

printImage() 函数用于打印图像(二维数组),方便查看填充前后的效果。

输出结果如下:

Before FloodFill:
1 1 1 0 0 
1 1 0 0 0 
1 1 0 0 0 
0 0 0 2 2 
0 0 0 2 2 

After FloodFill:
3 3 3 0 0 
3 3 0 0 0 
3 3 0 0 0 
0 0 0 2 2 
0 0 0 2 2 

小结

本篇关于FloodFill问题的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!

BFS算法篇——FloodFill问题的高效解决之道(上)_第1张图片

你可能感兴趣的:(常用算法讲解,算法,宽度优先)