Non-recursive implementation of Flood Fill algorithm?

ε祈祈猫儿з 提交于 2019-12-29 06:53:31

问题


I'm working on a small drawing application in Java. I'm trying to create a 'bucket-fill' tool by implementing the Flood Fill algorithm.

I tried using a recursion implementation, but it was problematic. Anyway, I searched around the web and it seems that for this purpose, a non-recursive implementation of this algorithm is recommended.

So I ask you:

Could you describe a non-recursive implementation of the Flood Fill algorithm? An actual code example, some pseudo-code, or even a general explanation will all be welcome.

I'm looking for simplest, or the most efficient implementation you can think of.

(Doesn't have to be Java specific).

Thank you


回答1:


I'm assuming that you have some sort of a grid where you receive the coordinates of the location from where you would like to fill the area.

Recursive flood fill algorithm is DFS. You can do a BFS to convert it to nonrecursive.

Basically the idea is similar in both the algorithms. You have a bag in which the nodes that are yet to be seen are kept. You remove a node from the bag and put the valid neighbors of the node back into the bag. If the bag is a stack you get a DFS. If it's a queue you get a BFS.

the pseudocode is roughly this.

flood_fill(x,y, check_validity)
   //here check_validity is a function that given coordinates of the point tells you whether
   //the point should be colored or not
   Queue q
   q.push((x,y))
   while (q is not empty)
       (x1,y1) = q.pop()
       color(x1,y1)

       if (check_validity(x1+1,y1))
            q.push(x1+1,y1)
       if (check_validity(x1-1,y1))
            q.push(x1-1,y1)
       if (check_validity(x1,y1+1))
            q.push(x1,y1+1)
       if (check_validity(x1,y1-1))
            q.push(x1,y1-1)

NOTE: make sure that check_validity takes into account whether the point is already colored or not.


  • DFS: Depth First Search
  • BFS: Breadth First Search



回答2:


You basically have two ways to implement a flood fill algorithm non-recursively. The first method has been clearly explained by sukunrt in which you use a queue to implement breadth first search.

Alternatively, you can implement the recursive DFS non-recursively by using an implicit stack. For example, the following code implements a non-recursive DFS on a graph that has nodes as integers. In this code you use an array of Iterator to keep track of the processed neighbors in every node's adjacency list. The complete code can be accessed here.

public NonrecursiveDFS(Graph G, int s) {
        marked = new boolean[G.V()];

        // to be able to iterate over each adjacency list, keeping track of which
        // vertex in each adjacency list needs to be explored next
        Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()];
        for (int v = 0; v < G.V(); v++)
            adj[v] = G.adj(v).iterator();

        // depth-first search using an explicit stack
        Stack<Integer> stack = new Stack<Integer>();
        marked[s] = true;
        stack.push(s);
        while (!stack.isEmpty()) {
            int v = stack.peek();
            if (adj[v].hasNext()) {
                int w = adj[v].next();
                if (!marked[w]) {
                    // discovered vertex w for the first time
                    marked[w] = true;
                    // edgeTo[v] = w;
                    stack.push(w);
                }
            }
            else {
                // v's adjacency list is exhausted
                stack.pop();
            }
        }
    }



回答3:


I am very good at flood fill algorythms, because I scanned all the available codes for them into a comparative sequence and I wrote a new version based on them.

So this information, That you will read, is the best possible implementation you can have on any programming platform.

All recursive and stack based implementations do not use organized memories or arrays to store the steps of pixels that they process.

Using an array declared explicitly and not relying on stack, you can rewrite all pixels your current known map of to scan and scanned pixels/voxels (if you are on 2d or 3d), at any line of your code and in any order withing the array.

The simplest and fastest version possible then becomes Recursion:

You recurse and write to THREE arrays copied as versions of the 2d/3d source array/image that you are writing from.

One for resulting flooded fill, One for source image, and one for "check this space next" ...

Your memory footprint is like 4 megs for a 1 meg source picture, using recursion.

Check this space next... is the magic array. You overwrite any extra recursions to the same check space and thereby unroll the recursion memory imprint by 1PowerN to being 1PowerX+Y.

I personally have achieved 2 gigapixels per second on a single core using that philosophy. it is the art of recursing through overwritable arrays. Simple. Figure it out and you will know the easiest, fastest, most simple to write, version possible writeable.

It's absurd to recurse through computer memory and create a new copy of every recursion result, when you are working on a source file with 1 million pixels or so. declare everything you need to write and read from withing the recursion as an array of the mapped XY stuff you are reading and writing, it just simplifies to three arrays sytaxed and a basic recursion.



来源:https://stackoverflow.com/questions/21865922/non-recursive-implementation-of-flood-fill-algorithm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!