📜  凸包 |第 2 组(格雷厄姆扫描)(1)

📅  最后修改于: 2023-12-03 15:22:37.240000             🧑  作者: Mango

凸包 | 第 2 组(格雷厄姆扫描)

凸包是计算几何学中的重要问题,其目的是寻找一个包含给定点集的最小凸多边形。本文将介绍第二组凸包算法——格雷厄姆扫描算法。

算法原理
  • 将点集按照 x 坐标从小到大排序。
  • 选出最左端的点,入栈。
  • 依次枚举剩余的点,如果该点是当前凸包的右转点,那么将栈顶元素出栈,一直重复此操作,直到没有右转点。
  • 将该点入栈。
  • 最后,栈内的点就是凸包的顶点,按照顺序输出即可。
算法流程
def graham_scan(points):
    def cross(a, b, c):
        return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])
        
    points = sorted(set(points), key=lambda x: (x[0], x[1]))
    if len(points) <= 1:
        return points
        
    lower = []
    for p in points:
        while len(lower) >= 2 and cross(lower[-2], lower[-1], p) < 0:
            lower.pop()
        lower.append(p)
        
    upper = []
    for p in reversed(points):
        while len(upper) >= 2 and cross(upper[-2], upper[-1], p) < 0:
            upper.pop()
        upper.append(p)
        
    return lower[:-1] + upper[:-1]
算法分析

格雷厄姆扫描算法的时间复杂度为 $O(n\log n)$。其优化主要集中在点集排序上。在实现过程中,我们还可以通过修改点之间的比较规则,来达到空间和时间的优化。

该算法还有许多其他的优化,比如使用卷包裹凸包的方法可以进一步优化时间复杂度,但这超过了本文的介绍范围。

使用场景

格雷厄姆扫描算法被广泛应用于凸包问题的求解,比如计算几何学、图形学、计算机视觉等领域。

总结

本文介绍了凸包问题的一个解法——格雷厄姆扫描算法。该算法通过扫描点集并维护一个栈来求解凸包。在实现过程中,我们需要注意点的排序、出栈以及入栈等操作的实现方法。