20 votos

Algoritmo para encontrar el punto más cercano

Tengo una lista de unos cientos de ciudades con su latitud/longitud. Dada otra localización (también en latitud/longitud) necesito encontrar la ciudad más cercana.

Como no utilizo ningún SIG, a estas alturas el algoritmo obvio es hacer un bucle para todas las ciudades, calculando la distancia entre los puntos.

Hacer el bucle es factible para mí, pero ¿hay algún algoritmo fácil de implementar para lograrlo de forma más eficiente? ¿O alguna librería Java ligera que pueda ayudar a resolverlo?

Notas : No necesito/quiero una solución SIG completa ni una biblioteca pesada/complicada. Prefiero una solución menos buena pero más fácil y ligera porque es lo único que necesito resolver.

25voto

cjstehno Puntos 131

Hace 20 años, cuando diseñaba un SIG de escritorio, me planteé exactamente esta cuestión. Necesitábamos encontrar distancias punto a punto de forma interactiva; nuestro objetivo era hacer los cálculos en menos de 1/2 segundo para miles de puntos. Las pruebas (¡en un PC 486 de 25 MHz!) demostraron que podíamos calcular todas las distancias, exactamente como describes (con el sencillo algoritmo obvio), tan rápido que no tenía sentido crear una solución más sofisticada, como una estructura de árbol cuádruple.

Para calcular distancias a un único punto "sonda", sus opciones incluyen (a) proyectar todos los puntos utilizando una proyección equidistante centrada en el punto sonda o (b) adoptar un modelo terrestre esférico y utilizar la proyección Fórmula Haversine . El primero es apropiado si se necesita la precisión de un modelo elipsoidal. En cualquier caso, los cálculos son razonablemente rápidos, probablemente menos de 1.000 ticks: se podría consultar alrededor de un millón de puntos por segundo con un solo procesador.

¿Suficientemente rápido para ti? Si no, el método de fuerza bruta se paraleliza fácilmente y escala directamente con el número de procesadores: basta con dividir los puntos entre los procesadores y luego hacer una comparación final del más cercano encontrado por cada procesador.

Si necesitas ir más rápido, puedes utilizar varias aproximaciones a los puntos de la pantalla. Por ejemplo, si se encuentra entre -88 y +88 grados de latitud y el punto más cercano encontrado hasta el momento está a 200 km, es imposible que cualquier punto cuya latitud difiera de la del punto sonda en más de 2 grados esté más cerca (porque en cualquier lugar de la Tierra, un grado de latitud supera unos 110 km). En muchos casos, este tipo de preselección puede permitir procesar cientos de millones de puntos por segundo.

4voto

Estoy de acuerdo con otros en que un simple bucle debería ser eficaz para "unos cientos de ciudades".

Dada su aplicación, tratar con distancias elipsoidales es probablemente una exageración importante: probablemente se trate de predicciones meteorológicas cuya localidad apenas se reduce a unos pocos metros. La geometría esférica es lo suficientemente sencilla como para que puedas hacerlo fácilmente en tu bucle.

Podría ser aún más sencillo (por ejemplo, utilizar delta lat como y y delta lon * cos(lat) como x y encontrar el mínimo x^2+y^2). Estás utilizando el coseno de la latitud objetivo, que sólo calculas una vez. Esto será cada vez más inexacta para las ciudades distantes, pero serán rechazados de todos modos por lo que no importa. Suponiendo que la ciudad más cercana se encuentre en un radio de doscientos kilómetros, las probabilidades de obtener un resultado diferente (ciudad más cercana) utilizando esta fórmula o una fórmula más precisa son bastante reducidas y sólo se producirían cuando las diferencias fueran lo suficientemente pequeñas como para que "qué previsión es más precisa" dependiera probablemente de otros factores (es decir, se perdiera en el ruido).

A menos que utilices un sistema embebido o un intérprete lento, probablemente puedas permitirte el lujo de utilizar los formales esféricos que otros sugieren.

1voto

Xetius Puntos 10445

Esto se suma a lo que ya se ha dicho, pero pensé que debía señalar la importancia de elegir una estructura de datos adecuada. Escribí mi propio código para una función K en .NET, y descubrí que el uso de colecciones eficientes aceleraba las cosas sustancialmente. Lo siento, no conozco la notación O para las velocidades exactas. Utilicé dos diccionarios para las coordenadas x e y con el ID del punto como clave. No sé Java así que no podía sugerir nada.

Salud, David

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X