0

I was wondering if there's a better way to , given a latitute and a longitude, find the closest bus stop than pass through the full ArrayList :

That's the BusStation Class :

    while(iteratore.hasNext()){    // for the full array size...
        tmp = (BusStation) iteratore.next();
        tmpDistance = getDistance(currentLat, currentLong, tmp.getStopLat(), tmp.getStopLon());
        if(tmpDistance < nearestDistance){  // if the distance is smaller ...
            nearestStop = tmp;  // i save the bus stop
            nearestDistance = tmpDistance;  // i save the distance too
        }
    }

That's the not efficient code , it works but every time the method is called it have to look through the full array with a complex of n.

How can we optimize it maiby with a Data Structure as the Binary Search Tree ?

The signature of the method should look like this :

public BusStation search(double currentLat, double currentLong){}
  • One can use Haversine Formula –  Nov 06 '17 at 10:49
  • What have you tried so far to optimize it yourself? – Lino Nov 06 '17 at 10:49
  • You can probably sort your `ArrayList` and then compare it to your values. Once, you found the optimum distance then you can break. The would change your complexity from `O(n^2)` to `O(n log n)` – Procrastinator Nov 06 '17 at 10:54
  • 2
    @Nehorai Haversine Formula isn't helpful. It gives you the distance between coordinates on a sphere. But doesn't help you find the smallest one efficiently. – slim Nov 06 '17 at 11:11
  • 2
    Maybe one of the methods from answers to this question could help https://stackoverflow.com/questions/1901139/closest-point-to-a-given-point Also, you could add your `getDistance()` method implementation, since it will most likely play a role in search optimisation. – PawelK Nov 06 '17 at 11:36

1 Answers1

1

Your core algorithm is about as good as you can do. However you can reduce the number of items you have to examine, by first sorting them into buckets based on location. For example, you could have a bucket for each 1km square of map.

If you know that every point on the map has a bus stop within 1km, then you only need to search through the stops in the target 1km square, and its 8 neighbours -- since a 1km radius circle drawn around any point on the centre square will be wholly contained in those 9 squares.

In many real-world circumstances, based on how you know the stops are spread you can probably come up with a cheap way to select a small set of squares guaranteed to contain the stop you're looking for. It could be very simple ("Nowhere on the map is further than 1km from a stop, so the 3x3 squares around the coordinates will contain one") or more technical ("in the centre of the city, a 3x3 search guarantees a hit; in the outskirts I need 5x5")

If the algorithm needs to be more general, then you can start by searching those 9 squares, then add squares overlapping an ever-larger circle.

radius = 1
while(true) {
    Set<Square> squares = difference(
         squaresContainedIn(radius), 
         squaresContainedIn(radius - 1));
    busStop = findNearest(coords, squares);
    if(busStop != null) {
        return busStop;
    }
    radius ++;
}

Beware though; you'll have to refine this algorithm a bit. It's possible for the closest item to be two squares away, even if there's a candidate one square away:

a 33333
b 32223
c 32123
d 32223
e 33333

  ABCDE

The closest stop by cartesian distance could be in E,c (second "search band") even though there's an item in the far corner of B,d (first "search band"). There are various ways you can make the algorithm handle this:

  1. When examining a band, disregard stops not in the current radius range. You will need to look at these squares again when considering the next iteration of radius.
  2. Or, when you find a candidate, don't consider it the "final" item until you've also searched the next band.

Or, depending on real-world requirements, you might decide that the occasional wrong (but still useful) answer is an acceptable trade-off for speed.

If you want to scale this approach up, you could use a QuadTree structure in which squares are nested within larger squares.

slim
  • 40,215
  • 13
  • 94
  • 127
  • 1
    Wikipedia has info on spacial indexing: https://en.wikipedia.org/wiki/Spatial_database#Spatial_index and your general problem is the Post-Office problem: https://en.wikipedia.org/wiki/Nearest_neighbor_search – slim Nov 06 '17 at 13:17