尽管遵循格雷厄姆扫描,但在凸包上产生了错误点

时间:2015-05-20 03:56:16

标签: java algorithm convex-hull grahams-scan

我已基本遵循{​​{3}}每一步,因为我编写了这个小凸包可视化器。它通常按预期工作,但在更高的输入尺寸下,通常会出现错误点。

程序首先填充ArrayList<Point>一定数量的随机生成的Point个对象。然后,它会找到Point最低y。如果多个Point个对象共享最低值,则使用具有最低x的对象。

接下来,相对于上面找到的特定ArrayList<Double>,它会生成每PointPoint个角度。它会快速排序这些角度及其对应的Point个对象,以生成带有排序值的ArrayList<Point>

下一步是我相信我的问题所在。首先,我复制ArrayList<Point>并将其称为edges(请注意,如果我没有使用原始ArrayList<Point>进行可视化,则无需克隆)对于任何三个有序Point 1}}} {} {}}中的对象我们会调用edgesAB,,如果从CAB则右转,然后BC应从船体中排除,并从B中删除。我通过取十字积的z值确定转弯是向右还是向左(负z意味着edgesAB是右转)。该程序删除任何导致右转的点并继续。

BC

为了循环多次,我主要添加了// loops through the orders points. any time a right turn is // encountered, the middle point is removed edges = new ArrayList<Point>(); edges.addAll(points); boolean changed = true; while (changed) { changed = false; for (int i = 0; i < edges.size() - 2; i++) { if (isRightTurn(edges.get(i), edges.get(i + 1), edges.get(i + 2))) { edges.remove(i + 1); changed = true; i--; } } if (isRightTurn(edges.get(edges.size() - 2), edges.get(edges.size() - 1), edges.get(0))) { edges.remove(edges.size() - 1); changed = true; } } // uses the z-value of the cross product of AB and AC (ABxAC) to determine // the direction of the turn. public static boolean isRightTurn(Point a, Point b, Point c) { if ((b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY()) * (c.getX() - a.getX()) < 0) return true; return false; } 变量,以便在跳过某些内容时进行验证。但是,错误仍然存​​在。有时,它按预期工作。 Successful convex hull

但是,通常至少有一些不正确的changed个对象。Unsuccessful convex hull

现在我注意到的是,直到左转弯发生,有多个Point正确左转,但仍然是错误的,因为它们最终位于应该是凸包的内部。这可能是回溯的问题吗?我觉得反复循环应该抓住这些情况。

1 个答案:

答案 0 :(得分:1)

以下是在对点进行排序后构建凸包的正确方法:

onHull = new List()
for p <- sorted list of points(including the first one)
    while onHull.size() >= 2 && isRight(onHull[onHull.size() - 2], onHull[onHull.size() - 1], p) 
        onHull.popBack()
    onHull.pushBack(p)
return onHull