我正在尝试设计一个算法,它可以以O((n+s) log n)的复杂度完成此任务。其中s是交叉点的数量。我尝试在互联网上搜索,但并没有找到类似的内容。
无论如何,我意识到这里关键是拥有一个良好的数据结构。我使用Java中的红黑树实现:TreeMap。我还使用了著名的扫描线算法来帮助我解决问题。
让我先解释一下我的设置。
我有一个调度器。这是一个基于最左坐标排序(升序)的PriorityQueue,其中包含我的圆形。scheduler.next()基本上轮询PriorityQueue,返回下一个最左边的圆形。
我也有一个状态。更确切地说,是扫描线状态。根据理论,该状态包含有资格相互比较的圆。在整个故事中拥有扫描线的意义在于,您能够排除许多候选项,因为它们根本不在当前圆的半径范围内。
我使用
该 TreeMap 可以保证插入/删除/查找的时间复杂度为 O(log n)。
算法本身的实现如下:
我测试了我的程序,很明显它具有O(n^2)的复杂度。我错过了什么吗?欢迎大家提供任何意见。
提前感谢!
无论如何,我意识到这里关键是拥有一个良好的数据结构。我使用Java中的红黑树实现:TreeMap。我还使用了著名的扫描线算法来帮助我解决问题。
让我先解释一下我的设置。
我有一个调度器。这是一个基于最左坐标排序(升序)的PriorityQueue,其中包含我的圆形。scheduler.next()基本上轮询PriorityQueue,返回下一个最左边的圆形。
public Circle next()
{ return this.pq.poll(); }
我这里还有一个包含4n个事件点的数组。假设每个圆都有两个事件点:最左边的x和最右边的x。调度程序有一个名为sweepline()的方法,可以获取下一个事件点。
public Double sweepline()
{ return this.schedule[pointer++]; }
我也有一个状态。更确切地说,是扫描线状态。根据理论,该状态包含有资格相互比较的圆。在整个故事中拥有扫描线的意义在于,您能够排除许多候选项,因为它们根本不在当前圆的半径范围内。
我使用
TreeMap<Double, Circle>
实现了该状态。其中 Double 是 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)的复杂度。我错过了什么吗?欢迎大家提供任何意见。
提前感谢!
O(n log n)
、O(n²)
还是O(2^n)
。 - Daniel Brückner