计算O((n + s)log n)中的圆交点

时间:2014-05-08 17:18:36

标签: java algorithm geometry complexity-theory intersection

我试图弄清楚如何设计一个能够以O((n + s)log n)复杂度完成此任务的算法。是交叉点的数量。我试过在互联网上搜索,却找不到东西。

无论如何,我意识到拥有良好的数据结构是关键。我在java:TreeMap中使用Red Black Tree实现。我还使用着名的(?)扫描线算法来帮助我处理我的问题。

让我先解释一下我的设置。

我有一个调度程序。这是一个PriorityQueue,我的圈子根据最左边的坐标排序(升序)。 scheduler.next()基本上轮询PriorityQueue,返回下一个最左边的圆圈。

public Circle next()
{ return this.pq.poll();    }

我这里还有一个包含4n个事件点的数组。授予每个圆圈有2个事件点:大多数左x和最右x。调度程序有一个方法sweepline()来获取下一个事件点。

public Double sweepline()
{ return this.schedule[pointer++];    }

我也有状态。扫描线状态更精确。根据该理论,状态包含有资格相互比较的圆圈。在整个故事中拥有扫描线的关键在于你能够排除很多候选人,因为他们根本不在当前圈子的半径范围内。

我使用TreeMap<Double, Circle>实施了状态。双倍为circle.getMostLeftCoord().

此TreeMap保证插入/删除/查找O(log n)。

算法本身的实现如下:

Double sweepLine = scheduler.sweepline();
Circle c = null;
while (notDone){
    while((!scheduler.isEmpty()) && (c = scheduler.next()).getMostLeftCoord() >= sweepLine)
        status.add(c);


    /*
     * Delete the oldest circles that the sweepline has left behind
     */
    while(status.oldestCircle().getMostRightCoord() < sweepLine)
        status.deleteOldest();

    Circle otherCircle;
    for(Map.Entry<Double, Circle> entry: status.keys()){
        otherCircle = entry.getValue();
        if(!c.equals(otherCircle)){
            Intersection[] is = Solver.findIntersection(c, otherCircle);
            if(is != null)
                for(Intersection intersection: is)
                    intersections.add(intersection);
        }
    }

    sweepLine = scheduler.sweepline();
}

编辑:Solver.findIntersection(c, otherCircle);返回最多2个交叉点。重叠的圆圈不被认为有任何交叉点。

SweepLineStatus的代码

public class BetterSweepLineStatus {

TreeMap<Double, Circle> status = new TreeMap<Double, Circle>();

public void add(Circle c)
{ this.status.put(c.getMostLeftCoord(), c);     }

public void deleteOldest()
{ this.status.remove(status.firstKey());    }

public TreeMap<Double, Circle> circles()
{ return this.status;       }

public Set<Entry<Double, Circle>> keys()
{ return this.status.entrySet();    }

public Circle oldestCircle()
{ return this.status.get(this.status.firstKey());   }

我测试了我的程序,我显然有O(n ^ 2)的复杂性。 我在这里错过了什么?你们可能提供的任何意见都非常受欢迎。

提前致谢!

3 个答案:

答案 0 :(得分:6)

您无法在n时间内找到平面中O(n log n)个圆圈的所有交点,因为每对圆圈最多可以有两个不同的交点,因此n个圆圈可以有最多n² - n个不同的交叉点,因此无法在O(n log n)时间内枚举它们。

获得n² - n交叉点最大数量的一种方法是将n个等半径r的圆心放置在长度为{{1}的相互不同的点上}}

Intersecting circles

答案 1 :(得分:4)

具有相同中心和半径的N个圆将具有N(N-1)/ 2对交叉圆,而通过使用足够大的圆使得它们的边界几乎是直线,您可以绘制具有N / 2条线的网格N / 2行中的每一行相交,也是N ^ 2。我会看一下,当你添加一个新的圆圈时,你的地图中通常会有多少条目。

您可以尝试为圆圈使用边界正方形并在待处理的正方形上保留索引,以便只能找到与查询正方形相交的y坐标的正方形(假设扫描线与y轴平行) )。这意味着 - 如果您的数据是友好的,您可以保留许多待处理的正方形,并且只检查其中的一些正方形中圆圈的可能交叉点。数据不友好,导致真正的N ^ 2交叉点总是会出现问题。

答案 2 :(得分:0)

圆圈与整个区域相比有多大?如果比例足够小,我会考虑将它们放入某种水桶中。它会使复杂性比O(n log n)复杂一点,但应该更快。