有没有办法进一步优化Graham Scan算法以找到凸包?

时间:2016-06-13 22:46:54

标签: java algorithm sorting convex-hull grahams-scan

我经历了陈的算法。对我来说似乎没有好转。 有没有办法可以用格雷厄姆扫描替换其他任何东西的排序部分?这样可以进一步减少O(nlogn)时间。 Java实现是首选。

1 个答案:

答案 0 :(得分:3)

优化分选步骤的最佳方法是避免考虑不属于凸包的点。这被称为Akl-Toussaint启发式http://www-cgrl.cs.mcgill.ca/~godfried/publications/fast.convex.hull.algorithm.pdf。你可以快速扫描所有顶点并找到形成点集的四边形(你可以得到四个点作为±(x + y),±(xy)中所有顶点的极值),然后只删除其中的所有顶点四边形。

在此之后你可以使用格雷厄姆的扫描或安德鲁的单调链算法 - 我最喜欢的,都是O(n log n)复杂度。 请注意,就像上面评论中提到的@Chill一样,Chan的方法是最佳的

实际上,这种方法比将其中一种算法应用于点集而不进行任何过滤要快得多。

我上面提到的论文在结论部分提到了“丢掉”的想法。这是一个小小的改进,因为我们可以扔掉大部分顶点,而搜索四边形本身。我正在为这个启发式附加一个片段。

/**
 * Given verts: Array(Points).
 */

/*
 * if we have more than 100 points use Akl-Toussaint heuristic to remove
 *  points that we know are surely not part of the hull.
 * S.G. Akl & Godfried Toussaint, 1977,  "A Fast Convex-hull Algorithm"
 */
if (verts.length > 100) {
    var min = Math.min,
        max = Math.max;
    var minU = minL = maxU = maxL = verts[0];
    var minUval = minU.x - minU.y;
    var minLval = minL.x + minL.y;
    var maxUval = maxU.x + maxU.y;
    var maxLval = maxL.x - maxL.y;
    var xMin = yMin = xMax = yMax = 0;
    var vertList = [];
    for (i = 0 ; i < verts.length; ++i) {
        var v = verts[i];
        var x = v.x;
        var y = v.y;
        if (!(x > xMin && x < xMax && y > yMin && y < yMax)) {
            vertList.push(v);
            var sum = x + y;
            var diff = x - y;
            if (diff < minUval) minU = v;
            if (diff > maxLval) maxL = v;
            if (sum < minLval) minL = v;
            if (sum > maxUval) maxU = v;
            minUval = minU.x - minU.y;
            maxLval = maxL.x - maxL.y;
            minLval = minL.x + minL.y;
            maxUval = maxU.x + maxU.y;
            xMin = max(minU.x, minL.x);
            yMin = max(minL.y, maxL.y);
            xMax = min(maxU.x, maxL.x);
            yMax = min(minU.y, maxU.y);
        }
    }

    // reset the vert's array, and do one more filtering pass 
    // on vertList
    verts.length = 0;
    for (i = 0 ; i < vertList.length; ++i) {
        var v = vertList[i];
        var x = v.x;
        var y = v.y;
        if (!(x > xMin && x < xMax && y > yMin && y < yMax))
            verts.push(v);
    }
    // verts now only contains a subset of vertices.
}
// Run a convexhull algorithm on verts.
// ...