簡體   English   中英

如何使兩點算法之間的最短路徑更快?

[英]How to make shortest path between two points algorithm faster?

我寫了這個算法。 它起作用(至少在我的短測試案例中),但在較大的輸入上花費的時間太長。 我怎樣才能讓它更快?

// Returns an array of length 2 with the two closest points to each other from the
// original array of points "arr"
private static Point2D[] getClosestPair(Point2D[] arr) 
{

    int n = arr.length;

    float min = 1.0f;
    float dist = 0.0f;
    Point2D[] ret = new Point2D[2];

    // If array only has 2 points, return array
    if (n == 2) return arr;

    // Algorithm says to brute force at 3 or lower array items
    if (n <= 3)
    {
        for (int i = 0; i < arr.length; i++)
        {
            for (int j = 0; j < arr.length; j++)
            {                   
                // If points are identical but the point is not looking 
                // at itself, return because shortest distance is 0 then 
                if (i != j && arr[i].equals(arr[j]))
                {
                    ret[0] = arr[i];
                    ret[1] = arr[j];
                    return ret;                   
                }
                // If points are not the same and current min is larger than
                // current stored distance
                else if (i != j && dist < min)
                {
                    dist = distanceSq(arr[i], arr[j]);
                    ret[0] = arr[i];
                    ret[1] = arr[j];
                    min = dist;
                }        
            }
        }

        return ret;
    }

    int halfN = n/2;

    // Left hand side
    Point2D[] LHS = Arrays.copyOfRange(arr, 0, halfN);
    // Right hand side
    Point2D[] RHS = Arrays.copyOfRange(arr, halfN, n);

    // Result of left recursion
    Point2D[] LRes = getClosestPair(LHS);
    // Result of right recursion
    Point2D[] RRes = getClosestPair(RHS);

    float LDist = distanceSq(LRes[0], LRes[1]);
    float RDist = distanceSq(RRes[0], RRes[1]);

    // Calculate minimum of both recursive results
    if (LDist > RDist)
    {
        min = RDist;
        ret[0] = RRes[0];
        ret[1] = RRes[1];
    }
    else
    {
        min = LDist;
        ret[0] = LRes[0];
        ret[1] = LRes[1];       
    }


    for (Point2D q : LHS)
    {
        // If q is close to the median line
        if ((halfN - q.getX()) < min)
        {
            for (Point2D p : RHS)
            {
                // If p is close to q
                if ((p.getX() - q.getX()) < min)
                {               
                    dist = distanceSq(q, p);        
                    if (!q.equals(p) && dist < min)
                    {
                        min = dist;
                        ret[0] = q;
                        ret[1] = p;
                    }

                }

            }
        }
    }

    return ret;
}

private static float distanceSq(Point2D p1, Point2D p2)
{
    return (float)Math.pow((p1.getX() - p2.getX()) + (p1.getY() - p2.getY()), 2);
}

我松散地遵循這里解釋的算法: http//www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html

和偽代碼的不同資源:

http://i.imgur.com/XYDTfBl.png

我無法更改函數的返回類型,或添加任何新參數。

謝謝你的幫助!

你可以做幾件事。

首先,您可以通過將第二次迭代更改為僅在“提醒”點上運行來非常簡單地縮短程序運行所需的時間。 這有助於您避免為每個值計算(i,j)(j,i) 為此,只需更改:

for (int j = 0; j < arr.length; j++)

for (int j = i+1; j < arr.length; j++)

但這仍然是O(n^2)

您可以通過迭代點並將每個點存儲在智能數據結構(最有可能是kd樹 )中來實現O(nlogn)時間。 在每次插入之前,找到已經存儲在DS中的最近點(kd樹在O(logn)時間內支持此值),並且它是最小距離的候選者。

我相信鏈接算法提到按一個坐標對數組進行排序,以便在第1點到第2000點給定LHS q,如果點200處的RHS p距離只有x距離超過“min”距離,則可以避免檢查剩余的201到2000分。

我想通了 - 大量減少了時間。 distanceSq函數錯誤。 最好使用Java的Point2D somepoint.distanceSq(otherpoint); 方法而不是。

至於n為3時的原始蠻力(在那種情況下它只會是3或2),線性搜索更好,更有效。

在蠻力條件之后,針對min變量的檢查在內部for循環中也是錯誤的。 使用平方距離很好,但是min不是平方的。 它保留了原始距離,這意味着min必須在兩個檢查中都是平方根(一次在外循環中,每次檢查一次在內部)。

所以,

if ((p.getX() - q.getX()) < min)

應該

if ((p.getX() - q.getX()) < Math.sqrt(min))

其他檢查也是如此。

謝謝大家的回答!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM