C ++中的快速rangesearch实现

时间:2019-06-26 12:48:25

标签: c++ performance

我将实现与matlab中的rangesearch相同的功能。问题在于数据确实很大(670万个3D点)。我读了Pairwise Distance Calculation in c++并改进了我的代码,但是它还不够快。由于对于这种数量的数据,计算距离矩阵非常耗费内存,因此不适用。我把代码放在这里。让我知道是否有一种方法可以使它更快。我不确定并行化在这里是否有用。数据按第一维排序,我想确保每个点的第一个邻居都是该点本身。

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;
}

1 个答案:

答案 0 :(得分:2)

您尝试解决的问题看起来像最近邻搜索n体模拟

当前代码的最坏情况复杂度是 O(n^2)。对于 n=6.7e6,这意味着大约一万亿次迭代。当然,破坏条件、并行性和低级优化会有所帮助,但生成的代码仍然会很慢。因此,您需要找到更好的算法

解决这类问题的常用方法是将所有元素放在一个 BSP-Tree 数据结构中(例如 QuadtreeOctree。这样的数据结构可以帮助您定位O(log(n)) 时间内某个位置附近的最近元素。因此,此方法的整体复杂度为 O(n log(n))

重要说明: 我假设半径很小。实际上,如果 radius 太大,那么您需要遍历整个树,从而导致二次复杂度。实际上,在这种情况下,写入输出的大小是二次的。因此,不幸的是,O(n^2) 将是最佳复杂度。