凸包算法的目的是从一个点集计算出最小的凸多边形,包围所有点。
1. Graham Scan
-
步骤:
- 选择基准点: 选择 y 坐标最小的点(如果有多个,选择 x 坐标最小的点)。
- 按极角排序: 计算所有点相对于基准点的极角,并按极角排序。
- 构建凸包: 使用栈来维护凸包的顶点。逐一检查点,保证凸包是凸的,弹出不符合条件的点,最终栈中的点即为凸包的顶点。
-
时间复杂度: O(n log n)(排序步骤占主导)
代码:
import numpy as np
def graham_scan(points):
points = sorted(points,key = lambda p:(p[0],p[1]))
def orientation(p,q,r):
return (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] -q[1])
def build_hull(points):
hull = []
for p in points:
while len(hull) >= 2 and orientation(hull[-2],hull[-1],p) <= 0:
hull.pop()
hull.append(p)
return hull
lower = build_hull(points)
upper = build_hull(reversed(points))
return np.array(lower[:-1] + upper[:-1])
points = np.array([[-5.90257, -0.22237], [1.03258, -0.533936], [0.907549, -0.134126],
[0.717333, 0.471533], [0.713893, 0.484054], [0.708021, 0.510585],
[0.668892, 0.637087], [0.5562, -0.748886], [0.552133, 1.01539],
[-1.36528, 1.202], [-1.49895, 1.6176], [-1.50235, 1.62983],
[-1.50702, 1.64434], [-1.51095, 1.65558], [-1.51498, 1.66897],
[-1.51726, 1.67879], [-1.5189, 1.68445], [-1.54057, 1.75716],
[-1.5986, -1.40478], [-2.28137, -1.61885], [-2.43108, -1.66877],
[-2.49418, 1.55916], [-4.34462, -2.27342], [-4.35825, 0.963766],
[-4.43426, -2.3003], [-5.8972, -0.250361]])
hull_points = graham_scan(points)
2. Jarvis March (Gift Wrapping)
-
步骤:
- 选择起点: 选择最左边的点作为起点。
- 寻找下一个点: 从当前点开始,选择相对于当前点所有其他点中极角最小的点作为下一个凸包点。
- 重复直到封闭: 继续选择极角最小的点,直到回到起点形成闭环。
-
时间复杂度: O(nh)(h 为凸包的顶点数,最坏情况下为 O(n^2))
代码:
import numpy as np
def jarvis_march(points):
hull = []
leftmost = np.argmin(points[:, 0])
point_on_hull = leftmost
while True:
hull.append(point_on_hull)
endpoint = (point_on_hull + 1) % len(points)
for i in range(len(points)):
if np.cross(points[endpoint] - points[point_on_hull], points[i] - points[point_on_hull]) < 0:
endpoint = i
point_on_hull = endpoint
if endpoint == leftmost:
break
return np.array(hull)
points = np.array([[-5.90257, -0.22237], [1.03258, -0.533936], [0.907549, -0.134126],
[0.717333, 0.471533], [0.713893, 0.484054], [0.708021, 0.510585],
[0.668892, 0.637087], [0.5562, -0.748886], [0.552133, 1.01539],
[-1.36528, 1.202], [-1.49895, 1.6176], [-1.50235, 1.62983],
[-1.50702, 1.64434], [-1.51095, 1.65558], [-1.51498, 1.66897],
[-1.51726, 1.67879], [-1.5189, 1.68445], [-1.54057, 1.75716],
[-1.5986, -1.40478], [-2.28137, -1.61885], [-2.43108, -1.66877],
[-2.49418, 1.55916], [-4.34462, -2.27342], [-4.35825, 0.963766],
[-4.43426, -2.3003], [-5.8972, -0.250361]])
hull_indices = jarvis_march(points)
hull_points = points[hull_indices]
print("Convex Hull points:", hull_points)