Java 计算O((n&x2B;s)对数n)中的圆交点
我正试图找出如何设计一种算法,能够以O((n+s)logn)的复杂度完成这项任务。是指交叉口的数量。我试着在互联网上搜索,但找不到真正的东西 无论如何,我意识到拥有一个好的数据结构是这里的关键。我正在使用java:TreeMap中的红黑树实现。我还使用著名的(?)扫描线算法来帮助我处理我的问题 让我先解释一下我的设置 我有一个时间表。这是一个优先队列,我的圆圈根据最左边的坐标排序(升序)Java 计算O((n&x2B;s)对数n)中的圆交点,java,algorithm,geometry,complexity-theory,intersection,Java,Algorithm,Geometry,Complexity Theory,Intersection,我正试图找出如何设计一种算法,能够以O((n+s)logn)的复杂度完成这项任务。是指交叉口的数量。我试着在互联网上搜索,但找不到真正的东西 无论如何,我意识到拥有一个好的数据结构是这里的关键。我正在使用java:TreeMap中的红黑树实现。我还使用著名的(?)扫描线算法来帮助我处理我的问题 让我先解释一下我的设置 我有一个时间表。这是一个优先队列,我的圆圈根据最左边的坐标排序(升序)scheduler.next()基本上轮询优先级队列,返回最左边的下一个圆圈 public Circle ne
scheduler.next()
基本上轮询优先级队列,返回最左边的下一个圆圈
public Circle next()
{ return this.pq.poll(); }
这里还有一个包含4n个事件点的数组。每个圆圈有2个事件点:最左x和最右x。调度程序有一个方法sweedline()来获取下一个事件点
public Double sweepline()
{ return this.schedule[pointer++]; }
我也有身份。扫描线状态将更加精确。根据这一理论,地位包括有资格相互比较的圈子。在整个故事中使用扫描线的意义在于,你可以排除很多候选对象,因为它们根本不在当前圆的半径范围内
我用一个树映射实现了状态。Double是圆。getMostLeftCoord()。
此树映射保证插入/删除/查找的O(日志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();
}
我测试了我的程序,我显然有O(n^2)的复杂性。
我错过了什么?你们能提供的任何意见都是非常受欢迎的
提前谢谢 N个圆心和半径相同的圆将有N(N-1)/2对相交圆,而通过使用足够大的圆,使其边界几乎是直线,您可以绘制一个网格,其中N/2条线与N/2条线中的每一条线相交,即N^2。当你添加一个新的圆圈时,我会看看地图上通常有多少条目
您可以尝试为圆使用边界正方形,并在挂起的正方形上保留索引,以便只能找到y坐标与查询正方形相交的正方形(假设扫描线平行于y轴)。这意味着-如果你的数据是友好的,你可以持有大量待处理的方块,并且只检查其中一些方块内圆的可能交点。数据不够友好,导致实际N^2个交点始终是一个问题。在
O(N log N)中,无法找到平面中N
圆的所有交点
时间,因为每对圆最多可以有两个不同的交点,因此n
圆最多可以有n²-n
个不同的交点,因此它们不能在O(n log n)
时间中枚举
获得最大数量的n²-n
交点的一种方法是将等半径r
的n
圆的中心放置在长度l<2r
直线上相互不同的点上
与整个区域相比,圆圈有多大?如果这个比率足够小,我会考虑把它们放入某种桶中。这将使复杂性比
O(n log n)
稍微复杂一点,但应该更快。“我显然有O(n^2)复杂性”-运行程序时无法判断这一点,因为否则可以解决暂停问题。您希望平面中n
圆的所有交点都在O(n log n)中
时间,对吗?对圆没有限制?@G.Bach这在科学上是不准确的,但在判断一个算法是O(n logn)
还是O(n²)
或O(2^n)
运行几个测试实例就足够了。@DanielBrückner这肯定不够好,因为这是一个正式的声明,一个正式的陈述需要正式的证明。运行测试足以告诉您预期的运行时间。这不是告诉复杂性的正确工具。@G.Bach我不需要任何形式的证明,但如果我设计一个O(nlogn)算法,我至少希望它在我所做的每一次运行的绘图上都能表现出它的行为。在这种情况下,我是在一个快速和肮脏的检查,以了解我是否做得很好。事实上,我所有的曲线图都显示出N翻倍的指数增长,对我来说,这肯定比O(N logn)更糟糕。参见mcdowella关于如何排列圆的直觉回答。这个问题仍然有效,但应该重新表述:计算O(nlogn+k)中的圆交点,其中N是圆的数量,k是交叉口的数量。我认为可以对圆的半径进行任何限制,因为建议的定位应该“缩放”。@GBach-我认为你是对的。这并不是一个关于圆的大小以及大小和相对位置的组合的问题。我只是觉得站在一个比我大得多的圆圈旁边很方便,我所能看到的都像一条直线。
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()); }