Sto cercando di capire come progettare un algoritmo in grado di completare questa attività con una complessità di O ((n + s log n). s è la quantità di intersezioni. Ho provato a cercare su internet, ma non ho trovato davvero qualcosa.Intersezioni cerchio di calcolo in O ((n + s) log n)
In ogni caso, mi rendo conto che avere una buona struttura dati è la chiave qui. Sto usando un'implementazione Red Black Tree in java: TreeMap. Io uso anche il famoso (?) Sweep-line algoritmo per aiutarmi ad affrontare il mio problema.
Lasciatemi spiegare prima la configurazione.
Ho un programmatore. Questo è un PriorityQueue con le mie cerchie ordinate (in ordine crescente) in base alla loro coordinata più a sinistra. scheduler.next()
fondamentalmente esegue il polling di PriorityQueue, restituendo la prossima cerchia più a sinistra.
public Circle next()
{ return this.pq.poll(); }
Ho anche un array con 4n punti evento qui. Garantire ad ogni cerchio ha 2 punti evento: la maggior parte sinistra x e la maggior parte destra x. Lo scheduler ha un metodo sweepline() per ottenere il prossimo evento.
public Double sweepline()
{ return this.schedule[pointer++]; }
Ho anche uno stato. Lo stato della linea di scorrimento è più preciso. Secondo la teoria, lo stato contiene i cerchi che possono essere confrontati l'uno con l'altro. Il punto di avere la linea di tendenza in questa storia è che sei in grado di escludere molti candidati perché semplicemente non sono nel raggio delle cerchie attuali.
Ho implementato lo stato con un TreeMap<Double, Circle>
. Doppio è il circle.getMostLeftCoord().
Questa TreeMap garantisce O (log n) per inserimento/rimozione/ricerca.
lo stesso algoritmo è implementato in questo modo:
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();
}
EDIT: Solver.findIntersection(c, otherCircle);
rendimenti max 2 punti di intersezione. Non si considera che cerchi sovrapposti abbiano intersezioni.
Il codice del 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()); }
ho provato il mio programma, e ho dovuto chiaramente O (n^2) la complessità. Cosa mi manca qui? Qualsiasi input che voi ragazzi potreste essere in grado di fornire è più che benvenuto.
Grazie in anticipo!
"e ho chiaramente avuto O (n^2) complessità" - questo è impossibile da capire dall'esecuzione di un programma, perché altrimenti si potrebbe risolvere il problema di interruzione. –
Vuoi tutti i punti di intersezione di 'n' cerchi nel piano in tempo' O (n log n) ', giusto? Nessun vincolo sui cerchi? –
Questa non è una prova. Sono solo dati sperimentali. –