// Keep track of a list of DistancedObjects, return shortest // David Eppstein, UC Irvine, 18 May 1997 // // interface: // new FastPair(): make empty list // new FastPair(Vector): make vector of DistancedObjects into new list // elements(): return Enumeration of objects in list // update(DistancedObject): object has changed, recompute its distances // restart(): all objects changed, recompute all distances // add(DistancedObject): add another object to the list // remove(DistancedObject): remove object from list // closestPair(): closest pair is returned obj and its neighbor // isEmpty(): true if no objs, false otherwise import java.util.*; import java.lang.*; public class FastPair { private Vector objs; public Enumeration elements() { return objs.elements(); } public boolean isEmpty() { return objs.isEmpty(); } // all objects changed, compute new neighbors for everyone public void restart() { // First, set all objects' neighbors to themselves // so we'll know which objects have actual neighbors already Enumeration enum = elements(); if (!enum.hasMoreElements()) return; // nothing to do while (enum.hasMoreElements()) { DistancedObject d = (DistancedObject) enum.nextElement(); d.distanceToNeighbor = Double.POSITIVE_INFINITY; d.neighbor = d; } // Start with the first object, and form a chain in which each // successive point chooses a neighbor among the so-far-unchosen points; // that neighbor then becomes the next to choose, etc, // until everyone has a neighbor DistancedObject o = (DistancedObject) objs.firstElement(); while (true) { enum = elements(); while (enum.hasMoreElements()) { DistancedObject d = (DistancedObject) enum.nextElement(); if (d.neighbor == d && d != o) { // eligible to be neighbor? double distToD = o.distanceTo(d); if (distToD < o.distanceToNeighbor || o.neighbor == o) { // better than old nbr? o.distanceToNeighbor = distToD; // yes, remember it o.neighbor = d; } } } if (o.neighbor == o) return; // didn't find any nbrs, end of line o = o.neighbor; // else go on to nbrs of new nbr } } // constructors public FastPair(Vector distancedObjects) { objs = distancedObjects; restart(); } public FastPair() { objs = new Vector(); } // Find closest pair, return one of them. // Caller beware, may crash if objs is empty. public DistancedObject closestPair() { DistancedObject bestObject = (DistancedObject) objs.firstElement(); double minDistance = Double.POSITIVE_INFINITY; Enumeration enum = elements(); while (enum.hasMoreElements()) { DistancedObject d = (DistancedObject) enum.nextElement(); if (minDistance > d.distanceToNeighbor) { bestObject = d; minDistance = d.distanceToNeighbor; } } return bestObject; } // compute new neighbor private void findNeighbor(DistancedObject x) { Enumeration enum = elements(); x.distanceToNeighbor = Double.POSITIVE_INFINITY; while (enum.hasMoreElements()) { DistancedObject d = (DistancedObject) enum.nextElement(); if (d != x) { double dx = x.distanceTo(d); if (dx < x.distanceToNeighbor) { x.distanceToNeighbor = dx; x.neighbor = d; } } } } // add new object public void add(DistancedObject x) { findNeighbor(x); objs.addElement(x); } // delete object public void remove(DistancedObject x) { objs.removeElement(x); Enumeration enum = elements(); while (enum.hasMoreElements()) { DistancedObject d = (DistancedObject) enum.nextElement(); if (d.neighbor == x) findNeighbor(d); } } // change set of distances associated with object already in data structure public void update(DistancedObject x) { Enumeration enum = elements(); while (enum.hasMoreElements()) { DistancedObject d = (DistancedObject) enum.nextElement(); if (d.neighbor == x) { double dx = d.distanceTo(x); if (dx <= d.distanceToNeighbor) d.distanceToNeighbor = dx; else findNeighbor(d); } } findNeighbor(x); } }