C 中的快速范围搜索实现

Fast rangesearch implementation in C++

本文关键字:范围 搜索 实现      更新时间:2023-10-16

我将与matlab中的rangesearch实现相同的功能。问题是数据确实很大(670万3D点(。我在C 中读取成对距离计算并改进代码,但还不够快。由于计算距离矩阵正在用于此数量数据的RAM消耗,因此不适用。我把代码放在这里。让我知道是否有一种方法可以更快。数据是在第一个维度上排序的,我想确保在每个点上,第一个邻居都是要点本身。

std::vector<std::vector<long int>> rangesearch(std::vector<std::vector<float>> &data, float radius) {
    float distmat = 0;
    float xdist = 0;
    std::vector<std::vector<long int>> indices(data.size());
    //This make sure that the first neighbour of each point is itself.
    for (unsigned long int i = 0; i < data.size(); i++) {
        indices[i].push_back(i);
    }
    // instead of computing sqrt() of distance, compute the 2nd power of radius once and compare it again and again which is faster
    radius = std::pow(radius, 2);
    for (unsigned long int i = 0; i < data.size(); i++) {
        for (long int j = i + 1; j < data.size(); j++) {
            xdist = std::pow(data[i][0] - data[j][0], 2);
            distmat = xdist + std::pow(data[i][1] - data[j][1], 2) + std::pow(data[i][2] - data[j][2], 2);
            if (distmat <= radius) {
                indices[i].push_back(j);
                indices[j].push_back(i);
            }
            //This is just to make the preprocessing faster. Data should be sorted based on X cordinates.
            //Then if the distance for x cordinate is bigger than radius it means that it will be even bigger
            // for the rest of the point so there is no need to check all of them and skip the rest!
            if (xdist > radius)
                break;
        }
    }
    return indices;
}

您试图解决的问题看起来像最近的neighbor搜索或a n-n-body Simulation 。。

当前代码的最坏情况复杂性是O(n^2)。使用n=6.7e6,这意味着大约一亿迭代。当然,破坏条件,并行性和低级优化将有所帮助,但是结果代码仍然非常慢。因此,您需要找到更好的算法。

解决此类问题的常见方法是将所有元素放在BSP-Tree数据结构(例如Quadtree或Octree(中。这样的数据结构可帮助您在O(log(n))时间内找到位置附近的最近元素。结果,此方法的总体复杂性是O(n log(n))

重要说明: 我以为半径很小。确实,如果radius太大,则需要在整个树上迭代,从而产生二次复杂性。实际上,在这种情况下,书面输出的大小是二次的。因此,不幸的是,O(n^2)将是最佳复杂性。