如何减少算法执行的时间

时间:2017-04-01 11:42:35

标签: c++ algorithm

我必须得到一个算法,它找到地球上最近的两个点。我编写了下面的代码,它适用于我的测试,但执行时间太长。我试图修改代码,但它没有帮助。也许有人会知道我该怎么做?

struct Points
{
    std::string key;
    double latitude;
    char latSign;
    double longitude;
    char longSign;
};

typedef std::pair<std::pair<std::string, std::string>, double> myType;

double toFraction(short deegres, short minutes)
{
    return (double)deegres + (minutes / 60.0);
}

double orthodroma(const Points &a, const Points &b)
{
    double radian = M_PI / 180;
    return acos((cos((90 - a.latitude) * radian) *
                 cos((90 - b.latitude) * radian)) +
                (sin((90 - a.latitude) * radian) *
                 sin((90 - b.latitude) * radian) *
                 cos((a.longitude - b.longitude) * radian))) *
           (180 / M_PI);
}

bool sortByLatitude(const Points &a, const Points &b)
{
    return a.latitude > b.latitude;
}

myType bruteForce(const std::vector<Points> &vec, int begin, int n)
{
    myType result;
    double min = 1000000;
    int _i, _j;
    if(n > 300)
    {
    }
    for(int i = begin; i < (n + begin) - 1; i++)
    {
        for(int j = i + 1; j < n + begin; j++)
        {
            double tmp;
            tmp = orthodroma(vec[i], vec[j]);
            if(tmp < min)
            {
                min = tmp;
                _i = i;
                _j = j;
            }
        }
    }
    result.first.first = vec[_i].key;
    result.first.second = vec[_j].key;
    result.second = min;
    return result;
}

myType divideAndConquer(std::vector<Points> &vec, int begin, int n)
{
    if(n <= 3)
    {
        return bruteForce(vec, begin, n);
    }
    std::sort(vec.begin(), vec.end(), sortByLatitude);
    int middle = n / 2;
    Points point = vec[middle];
    myType left = divideAndConquer(vec, begin, middle);
    myType right = divideAndConquer(vec, middle, (n - middle));
    bool which;
    double minDist = std::min(left.second, right.second);
    if(left.second < right.second)
        which = false;
    else
        which = true;
    std::vector<Points> arr;
    for(int i = 0; i < n; i++)
    {
        if(abs(vec[i].latitude - point.latitude) < minDist)
        {
            arr.push_back(vec[i]);
        }
    }
    int size = arr.size();
    if(size < 2)
    {
        if(which)
            return right;
        else
            return left;
    }
    else
    {
        myType one = bruteForce(arr, 0, size);
        if(which)
        {
            if(one.second < right.second)
                return one;
            else
                return right;
        }
        else
        {
            if(one.second < left.second)
                return one;
            else
                return left;
        }
    }
}

PS。我必须使用分治法。

2 个答案:

答案 0 :(得分:0)

一些可能会稍微改善性能的想法:

  • 只对数组进行一次排序(在第一次递归调用分治法之前)。

  • 将点添加到arr向量中时,您可以从中间位置开始,先向前移动,然后向后移动。优点是,只要一个点离中间点足够远,就可以打破每个循环。由于数组按纬度排序,因此可以保证其余的点都在所需的范围之外。

  • 您可以将另一个参数传递给divideAndConquer方法,表示到目前为止已知的最小距离。这可以导致更小的arr数组,更快地处理。目前,可能是左子阵列的距离非常小。但是,在求解正确的子数组时,递归调用当前没有关于已找到的小距离的信息。

答案 1 :(得分:0)

要找到最近的两个点,首先需要检查每个点到最近点的距离。

您应该使用KD树进行快速最近邻居查找。您可以使用可比较的距离来保存sqrt()操作。

这是一个很棒的kd tree library