How can I group an array of rectangles into “Islands” of connected regions?

前端 未结 8 2149
难免孤独
难免孤独 2021-02-04 08:12

The problem

I have an array of java.awt.Rectangles. For those who are not familiar with this class, the important piece of information is that they provid

8条回答
  •  南旧
    南旧 (楼主)
    2021-02-04 08:47

    I'm not up on my java foo, but I guess the problem is that you're removing items from your list while iterating the list. Depending on the implementation of the container type this can have big problems. Someone with more Java knowledge may be able to confirm or deny this.

    This SO Question seems to confirm my suspicions.

    After googling a bit it seems that java iterators support a remove method, so instead of

    allRects.remove(rect);
    

    you should use an iterator and then use

    rect_i.remove();
    

    and the same for

    list.remove(rect);
    

    Although I think this will still get you in trouble since you are modifying the same list at a lower level in the call stack.

    My version:

    ArrayList rects = new ArrayList(rectArray);
    ArrayList> groups = new ArrayList>();
    while (!rects.isEmpty)
    {
        ArrayList group = new ArrayList();
        ArrayList queue = new ArrayList();
        queue.add(rects.remove(0));
        while (!queue.isEmpty)
        {
            rect_0 = queue.remove(0);
            rect_i = rects.iterator();
            while (rect_i.hasNext())
            {
                Rectangle rect_1 = rect_i.next();
                if (rect_0.intersects(rect_1))
                {
                    queue.add(rect_1);
                    rect_i.remove();
                }
            }
            group.add(rect_0);
        }
        groups.add(group);
    }
    

    Note: I think the code's correct now, but I wrote this up just from reference docs and I'm no Java coder, so you may need to tweak.

    As an aside, this type of naive algorithm is fine if you have a small list of rectangles that you need to check, but if you want to do this for very large lists, then you will want to use a much more efficient algorithm. This naive algorithm is O(n^2), a smarter algorithm that first sorts all rectangle corners lexicographically and then performs a plane sweep and does range intersection checking on the sweep line would result in a relatively straightforward O(n log n) algorithm.

提交回复
热议问题