繁体   English   中英

如何优化使用嵌套 for 循环的代码?

[英]How can I optimize my code that uses nested for loops?

我正在努力解决一个问题,我需要确定一个Point是否位于连接其他两个Points的线上。 例如,如果我有Point a, b, c ,我想确定c是否在连接ab的线段上。 在我的代码中,我有一个点, me (示例中的 a)和两个点列表, hits (示例中的 b)和reachable (示例中的 c)。 对于命中中的每个点,我想确定在连接我和命中点的线段上是否有任何可到达的点。 如果该线段上有一个点,则需要减少 numHits。 这是我的代码:

Point me; //Point a from the example above
ArrayList<Point> hits = new ArrayList<>();  //a list of Point b's from the example above
ArrayList<Point> reachable = new ArrayList<>();  //a list of point c's from the example above

for(Point hit : hits) {
    for(Point p : reachable) {
        if(!hit.equals(p) && !me.equals(p)) {
            //find the equation of a line from me to hit
            if(hit.x - me.x == 0) { //if the line has an undefined slope... if the line is vertical
                if( (((p.y <= hit.y) && (p.y >= me.y)) || ((p.y >= hit.y) && (p.y <= me.y))) && p.x - me.x == 0) {  //if there is any occupied point on that line in between me and the hit, that point blocks the hit
                    numHits--;
                    break;
                }
            } else {
                //create a line from me to the hit... if there is any occupied point on that line in between me and the hit, that point blocks the hit
                double deltaY = hit.y - me.y;
                double deltaX = hit.x - me.x;

                double m = deltaY / deltaX; //slope
                double b = me.y - (double)(m*me.x);  //y intercept

                if((double) p.y == ((double)(m * p.x) + b)) {  //if this point is on the same line 
                    if( ((p.x <= hit.x && p.x >= me.x) && (p.y <= hit.y && p.y >= me.y)) ||
                                ((p.x <= hit.x && p.x >= me.x) && (p.y >= hit.y && p.y <= me.y)) || 
                                ((p.x >= hit.x && p.x <= me.x) && (p.y >= hit.y && p.y <= me.y)) ||
                                ((p.x >= hit.x && p.x <= me.x) && (p.y <= hit.y && p.y >= me.y))) {  //if the point is in between me and the hit
                        numHits--;
                        break;
                    }
                }
            }
        }
    }
}

我的代码用于确定mehits中的每个点之间是否有任何reachable的点,它只会变得非常慢,较大的hitsreachable的 get。 例如,如果 hits 的大小为 780,000,reachable 的大小为 1,500,000,则代码需要很长时间才能运行。 我想知道如何优化它以更快地运行。 我不确定瓶颈问题是出在循环本身还是出在循环内的代码中。 非常感谢任何帮助或优化想法。 谢谢!

我建议您查看Line2D.Double 它有许多方法,包括确定点甚至线是否在给定线段上的方法。

我还建议您使用memoize来记住您可能已经遇到的现有点和其他信息。 这样你就不会一直重复计算。 因为浮点运算可能会导致微小的差异,您可能不得不使用一些可接受的error来确定结果的有效性。

优化代码的一种方法是将点移到原点,然后将所有点划分到各自的象限,所以现在你只需要比较相同象限中的点。

下面我会写一个粗略的算法。

1. Shift the point me to origin

2. Shift all other points, ie hits and reachable to origin ( this can be done by  subtracting X and Y of point me from all other X and Y ) 

3. Now divide hits and reachable to 4 quadrants based on their X and Y components, now you will have 4 arrays for hits and 4 arrays for reachable


4. You can also reduce the number of points in reachable by comparing them against the greatest point in hits like below, do this for all quadrants


    a. find greatest |X| (mode(X)) and greatest |Y| of hits in each quadrant, lets call it me.|x| and me.|y|

     b. for(Point p : reachable) {
              if(p.|x| > me.|x| or p.|y| > me.|y|) then remove p from reachable }
    since these points will be outside of the  line segment formed by me and hits

5. Now you can compare the values, using nested for loops as you did, you will have to use different conditions for each quadrant

不要忘记添加边缘条件并从原点移回

将每条线acx = 0y = 0 ,以较小的幅度为准(以最小化舍入误差)。 排序或 hash 这些拦截,保留对每个c的引用,确保保留重复项。

然后对于每一行ab ,也将其投影到x = 0y = 0 ,以较小的幅度为准,并在排序或散列集合中搜索匹配的截距。 这为您提供了少量候选线段,它们都通过abc位于同一条线上; 您只需要检查该点是否位于端点内( ax < c.x < bxax > c.x > bx并再次为y )。

小心舍入错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM