Algorithm 在有限集合中寻找与另一点最近点的有效算法

Algorithm 在有限集合中寻找与另一点最近点的有效算法,algorithm,geometry,computational-geometry,Algorithm,Geometry,Computational Geometry,我有一个约30k个位置的列表L(写为经度/纬度对),和一个约1m个事件的列表E(写为经度/纬度对),每个事件发生在L中的一个点上。我想标记E中的每个事件及其在L中的对应位置。但L和E中的坐标四舍五入不同——E到小数点后五位,L到13个表面上相同的坐标实际上可以相差约10^-5度,或约1米。(L中的点之间至少相隔10米) 因此,我需要L中距离E的每个点最近的点;明显的O(| L | | E |)暴力算法太慢了。与E相比,L足够小,因此预处理L并将预处理时间分摊到E上的算法是好的。这是一个经过充分研

我有一个约30k个位置的列表L(写为经度/纬度对),和一个约1m个事件的列表E(写为经度/纬度对),每个事件发生在L中的一个点上。我想标记E中的每个事件及其在L中的对应位置。但L和E中的坐标四舍五入不同——E到小数点后五位,L到13个表面上相同的坐标实际上可以相差约10^-5度,或约1米。(L中的点之间至少相隔10米)

因此,我需要L中距离E的每个点最近的点;明显的O(| L | | E |)暴力算法太慢了。与E相比,L足够小,因此预处理L并将预处理时间分摊到E上的算法是好的。这是一个经过充分研究的问题吗?我能找到的链接是针对相关但不同的问题的,比如在一个集合中找到一对点之间的最小距离


可能相关:,但我看不出将L预处理成Voronoi图将如何节省我的计算时间。

是的,你是对的。首先,您可以使用该方法构建位置L在O(| L | log | L |)时间内的点集的Voronoi图。有各种各样的实现可以使用,这将是最常见的实现之一

现在你有了一个O(| L |)大小的平面的分区。要允许O(log | L |)近邻查询,您需要在Voronoi图的顶部设置一个搜索结构。一种常见的方法是使用Dobkin-Kirkpatrick层次结构,详细信息可以在不同的层次结构中找到。此方法支持O(log | L |)查询,并且只需要O(| L |)大小。(在中也提到。)

然后| E |查询可以在O(| E | log | L |)时间内完成

另一种方法是使用。从实现的角度来看,它们可能工作量较少,并且提供相同的复杂性(据我所知)。
快速搜索发现这两个实现可能值得测试:,。

这可以相当直接地应用。大多数GIS库都应该提供这样做的工具

我自己的经验仅限于使用。我创建了L项的索引。可以直接使用点,也可以使用表示点周围不确定性的边界框。然后,R-树支持对n个最近的相邻点/边界框进行有效的(对数(L)时间)查询

我成功使用的实现被包装到一个名为的python库中

但是,请注意,此特定工具仅在使用欧几里德x、y坐标时才准确。使用远离赤道的纬度经纬仪时,尤其是当你想覆盖一个地理上大的区域时,可能会有很大的误差。在我的情况下,我被限制在一个使用东/北的国家。我不知道哪些库提供了使用大圆距离处理问题的支持,但它们肯定应该可用。

根据您的描述:

  • E中的每个点与L中的一个点相同,四舍五入到小数点后五位。因此,E中的每一点都与L中的匹配点相差约1米
  • L中的点之间至少相隔10米
解决方案:将L中的坐标旋转到与E相同的精度,并匹配相等的对

说明:舍入有效地将每个点映射到正方形网格上的最近邻点。只要栅格分辨率(四舍五入到五位小数时为1米)低于L中两点之间最小距离的一半(~10/2米),就可以使用

为了获得最佳性能并充分利用| L |我的库包含一个类 它实现了。这适用于任何数据 有真实距离度量的地方;测地距离 满足这一标准。 基本上,您可以使用
L
位置初始化类 然后针对每个
E
事件 询问最近的地点。计算机网络的崩溃 费用如下

set-up cost: L log L
cost per query: log L
cost of all queries: E log L
total cost: (L + E) log L
(这些是base-2日志。)下面是执行查找的代码。在30k地点和1M事件上运行此程序大约需要40秒,总共需要16M的测地距离计算。(暴力方式大约需要21小时。)

//从locations.txt读取lat/lon位置和从locations.txt读取lat/lon事件
//events.txt。对于每个事件,打印到最接近的.txt:事件的索引
//最近的位置及其距离。
//需要CLIB 1.47或更高版本
//编译并链接到
//g++-o.cpp-lGeographic\
//-L/usr/local/lib-Wl,-rpath=/usr/local/lib
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
使用clib;
//保持地理坐标的结构。
结构位置{
双lat,lon;
位置(双横向=0,双纵向=0)
:lat(lat),lon(lon){
};
//用于计算两个位置之间距离的类。
类距离计算器{
私人:
测地线;
公众:
显式距离计算器(常数测地线和测地线)
:_geod(geod){}
双运算符()(常量位置a、常量位置b)常量{
双s12;
_大地逆(a.lat,a.lon,b.lat,b.lon,s12);
返回s12;
}
};
int main(){
//定义距离函数对象
距离计算器距离(测地线::WGS84());
//读入位置
矢量LOC;
{
双lat,lon;
ifstream是(“locations.txt”);
while(is>>lat>>lon)
位置推回(位置(横向、纵向);
}
//构造最近邻对象
近邻
位置集(位置、距离);
ifstream是(“events.txt”);
流操作系统(“closest.txt”);
双lat,lon,d;
向量k;
while(is>>lat>>lon){
pos事件(纬度、经度);
d=位置集搜索(位置、距离、事件、k);

好的。我跳过了你的大部分帖子,因为里面有太多无用的信息。基本上,你有一个由30k个XY点组成的列表“L”(如果是y,称之为lat/long)
// Read lat/lon locations from locations.txt and lat/lon events from
// events.txt.  For each event print to closest.txt: the index for the
// closest location and the distance to it.

// Needs GeographicLib 1.47 or later

// compile and link with
// g++ -o closest closest.cpp -lGeographic \
//   -L/usr/local/lib -Wl,-rpath=/usr/local/lib

#include <iostream>
#include <vector>
#include <fstream>
#include <GeographicLib/NearestNeighbor.hpp>
#include <GeographicLib/Geodesic.hpp>

using namespace std;
using namespace GeographicLib;

// A structure to hold a geographic coordinate.
struct pos {
  double lat, lon;
  pos(double lat = 0, double lon = 0)
    : lat(lat), lon(lon) {}
};

// A class to compute the distance between 2 positions.
class DistanceCalculator {
private:
  Geodesic _geod;
public:
  explicit DistanceCalculator(const Geodesic& geod)
    : _geod(geod) {}
  double operator() (const pos& a, const pos& b) const {
    double s12;
    _geod.Inverse(a.lat, a.lon, b.lat, b.lon, s12);
    return s12;
  }
};

int main() {
  // Define a distance function object
  DistanceCalculator distance(Geodesic::WGS84());

  // Read in locations
  vector<pos> locs;
  {
    double lat, lon;
    ifstream is("locations.txt");
    while (is >> lat >> lon)
      locs.push_back(pos(lat, lon));
  }

  // Construct NearestNeighbor object
  NearestNeighbor<double, pos, DistanceCalculator>
    locationset(locs, distance);

  ifstream is("events.txt");
  ofstream os("closest.txt");

  double lat, lon, d;
  vector<int> k;
  while (is >> lat >> lon) {
    pos event(lat, lon);
    d = locationset.Search(locs, distance, event, k);
    os << k[0] << " " << d << "\n";
  }
}