📅  最后修改于: 2023-12-03 15:22:22.539000             🧑  作者: Mango
凸包是由一系列点所组成的最小凸多边形。而分而治之算法是一种将问题分解为更小更容易解决的子问题,再将每个子问题的解合并为总问题的解的算法。在计算凸包时使用分而治之算法可以大大提高算法的效率。
通过分而治之算法求解凸包需要两个步骤:分解和合并。
分解步骤将点集合分成两个或多个部分,对每一部分递归地求解凸包。具体实现时可以按照横坐标的大小将点集合分成两个部分,再在两个部分中进行递归求解。
def divide(points):
n = len(points)
if n <= 5:
return brute(points)
mid = n // 2
left = divide(points[:mid])
right = divide(points[mid:])
return merge(left, right)
合并步骤将求解得到的两个凸包合并为总凸包。具体实现时需要考虑两个凸包相交的情况,将相交的部分去掉后再将两个凸包拼接起来。
def merge(left, right):
l = len(left) - 1
r = len(right) - 1
while cross(left[l] - left[l - 1], right[1] - right[0]) > 0 and cross(right[r] - right[r - 1], left[1] - left[0]) > 0:
if left[l].y < right[r].y:
r -= 1
else:
l -= 1
lower = left[:l + 1] + right[:r + 1]
l = len(left) - 1
r = len(right) - 1
while cross(left[l] - left[l - 1], right[1] - right[0]) < 0 and cross(right[r] - right[r - 1], left[1] - left[0]) < 0:
if left[l].y > right[r].y:
r -= 1
else:
l -= 1
upper = left[l:] + right[r:]
return lower + upper[1:-1]
当分解得到的点集合大小不超过5时采用暴力求解的方式。
def brute(points):
hull = []
for i in range(len(points)):
hull.append(points[i])
while len(hull) > 2 and cross(hull[-1] - hull[-2], hull[-3] - hull[-2]) > 0:
hull.pop(-2)
return hull
使用分而治之算法求解凸包的时间复杂度为O(n log n)。在实际应用中可以通过将点集合按照x坐标的大小排序来进一步提高算法效率。
分而治之算法可以大大提高凸包的求解效率,适用于大规模的点集合。程序员可以通过学习这个算法来提高自己的程序设计能力,扩展自己的算法解决方案。