floodfile

Pseudocode for Breadth-First Scanning

This code uses a trick to not use extra space, marking nodes to be visited as in component -2 and actually assigning them to the current component when they are actually visited. 

# component(i) denotes the
# component that node i is in
 1 function flood_fill(new_component) 

 2 do
 3   num_visited = 0
 4   for all nodes i
 5     if component(i) = -2
 6       num_visited = num_visited   1
 7       component(i) = new_component
 8       for all neighbors j of node i
 9         if component(j) = nil
10           component(j) = -2
11 until num_visited = 0 

12 function find_components 

13  num_components = 0
14  for all nodes i
15    component(node i) = nil
16  for all nodes i
17    if component(node i) is nil
18      num_components =
                 num_components   1
19      component(i) = -2
20      flood_fill(component
                        num_components)

Running time of this algorithm is O(2), where N is the numbers of nodes. Every edge is traversed twice (once for each end-point), and each node is only marked once.

 web:

Flood fill,  also called seed fill, is analgorithm that determines the area connected to a given node in a multi-dimensional array. It is used in the "bucket" fill tool of paint programs to determine which parts of a bitmap to fill with color
the algorithms
The flood fill algorithm takes three parameters: a start node, a target color, and a replacement color. The algorithm looks for all nodes in the array which are connected to the start node by a path of the target color, and changes them to the replacement color. There are many ways in which the flood-fill algorithm can be structured, but they all make use of aqueue orstack data structure, explicitly or implicitly.
从上面的算法介绍可知,凡是会搜索的同学就能很轻易地掌握floodfill。因为floodfill算法从大体而言可以细分为两种算法思想,一种是DFS,一种是BFS。以下讲介绍两大种常用的算法,并简单分析其中用到的dfs和bfs。
1. per-pixel fill  (点点填充)
                                                          
recursive flood-fill with 4 directions                      recursive flood-fill with 8 directions
这两个有一个小区别,就是8方向的算法是在4方向的算法的基础上添加了四个方向(左上、左下、右上、右下),因此造成的结果是8方向的算法有可能会 “leak through sloped edges of 1 pixel thick”。至于其它方面则是完全一样,下面所有的算法都是基于4方向的。
dfs的搜索思想(递归)写的代码:
Flood-fill (node, target-color, replacement-color):
1. If the color of node is not equal to target-color, return.
2. Set the color of node to replacement-color.
3. Perform Flood-fill (one step to the west of node,target-colorreplacement-color).
    Perform Flood-fill (one step to the east of node,target-colorreplacement-color).
    Perform Flood-fill (one step to the north of node,target-colorreplacement-color).
    Perform Flood-fill (one step to the south of node,target-colorreplacement-color).
4. Return.
bfs的搜索思想(队列)写的代码:
Flood-fill (node, target-color, replacement-color):
1. Set Q to the empty queue.
2. If the color of node is not equal to target-color, return.
3. Add node to the end of Q.
4. While "Q" is not empty: 
5.     Set "n" equal to the first element of "Q"
6.     If the color of n is equal to target-color, set the color of n to replacement-color.
7.     Remove first element from "Q"
8.     If the color of the node to the west of n is target-color, set the color of that node to replacement-color, add that node to the end of Q.
9.     If the color of the node to the east of n is target-color, set the color of that node to replacement-color, add that node to the end of Q.
10.    If the color of the node to the north of n istarget-color, set the color of that node to replacement-color, add that node to the end of Q.
11.    If the color of the node to the south of n istarget-color, set the color of that node to replacement-color, add that node to the end of Q.
12. Return.
以上两种小算法的问题在于,如果填充的面积较大的话,程序很容易爆掉。究其原因,就是搜索的深度过大或队列的长度不够造成的。因此为了减少搜索深度或进队列的元素个数,可以用线方式代替点方式。而这样做还有一个好处就是填充速度的提高。
2. scanline fill  (扫描线填充)
//stack friendly and fast floodfill algorithm (递归深搜的写法)
void floodFillScanline(int x, int y, int newColor, int oldColor)
{
    if(oldColor == newColor) return;
    if(screenBuffer[x][y] != oldColor) return;
      
    int y1;
    
    //draw current scanline from start position to the top
    y1 = y;
    while(y1 < h && screenBuffer[x][y1] == oldColor)
    {
        screenBuffer[x][y1] = newColor;
        y1 ;
    }    
    
    //draw current scanline from start position to the bottom
    y1 = y - 1;
    while(y1 >= 0 && screenBuffer[x][y1] == oldColor)
    {
        screenBuffer[x][y1] = newColor;
        y1--;
    }
    
    //test for new scanlines to the left
    y1 = y;
    while(y1 < h && screenBuffer[x][y1] == newColor)
    {
        if(x > 0 && screenBuffer[x - 1][y1] == oldColor) 
        {
            floodFillScanline(x - 1, y1, newColor, oldColor);
        } 
        y1 ;
    }
    y1 = y - 1;
    while(y1 >= 0 && screenBuffer[x][y1] == newColor)
    {
        if(x > 0 && screenBuffer[x - 1][y1] == oldColor) 
        {
            floodFillScanline(x - 1, y1, newColor, oldColor);
        }
        y1--;
    } 
    
    //test for new scanlines to the right 
    y1 = y;
    while(y1 < h && screenBuffer[x][y1] == newColor)
    {
        if(x < w - 1 && screenBuffer[x 1][y1] == oldColor)
        {           
            floodFillScanline(x 1, y1, newColor, oldColor);
        } 
        y1 ;
    }
    y1 = y - 1;
    while(y1 >= 0 && screenBuffer[x][y1] == newColor)
    {
        if(x < w - 1 && screenBuffer[x 1][y1] == oldColor)
        {
            floodFillScanline(x 1, y1, newColor, oldColor);
        }
        y1--;
    }
}
//The scanline floodfill algorithm using our own stack routines, faster (广搜队列的写法)
void floodFillScanlineStack(int x, int y, int newColor, int oldColor)
{
    if(oldColor == newColor) return;
    emptyStack();
    
    int y1; 
    bool spanLeft, spanRight;
    
    if(!push(x, y)) return;
    
    while(pop(x, y))
    {    
        y1 = y;
        while(y1 >= 0 && screenBuffer[x][y1] == oldColor) y1--;
        y1 ;
        spanLeft = spanRight = 0;
        while(y1 < h && screenBuffer[x][y1] == oldColor )
        {
            screenBuffer[x][y1] = newColor;
            if(!spanLeft && x > 0 && screenBuffer[x - 1][y1] == oldColor) 
            {
                if(!push(x - 1, y1)) return;
                spanLeft = 1;
            }
            else if(spanLeft && x > 0 && screenBuffer[x - 1][y1] != oldColor)
            {
                spanLeft = 0;
            }//
写这一部分是防止因为同一列上有断开的段而造成的可能的“没填充”
            if(!spanRight && x < w - 1 && screenBuffer[x 1][y1] == oldColor) 
            {
                if(!push(x 1, y1)) return;
                spanRight = 1;
            }
            else if(spanRight && x < w - 1 && screenBuffer[x 1][y1] != oldColor)
            {
                spanRight = 0;
            } //写这一部分是防止因为同一列上有断开的段而造成的可能的“没填充”
            y1 ;
        }
    }
}
以上两个小算法填充的方向都是纵向填充,你也可以修改成横向填充。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值