📜  凸包|单调链算法(1)

📅  最后修改于: 2023-12-03 14:50:10.250000             🧑  作者: Mango

凸包 | 单调链算法

凸包是指包裹住一组点集中所有点的最小凸多边形。凸包可以应用于计算几何和图像处理等领域,例如:给定一组点,计算它们的闭包,或者通过它们找出最远点对等等。

凸包有两种算法,分别是朴素算法和单调链算法。在本文中我们将介绍单调链算法。

算法思想

单调链算法是一种基于栈的算法,它的核心思想是:将点按照 x 坐标进行排序,然后分别求出上凸壳和下凸壳,再将两个凸壳合并,即可得到最终的凸包。

具体来说,我们假设点集为 P,将其按照 x 坐标排序。从左到右遍历这些点,对于每个点,我们都可以确定它在凸包中的位置:

  • 如果当前点在上凸壳上,则将其入栈;
  • 如果当前点在下凸壳上,则将栈中的点出栈,直到栈顶点和新加入的点和它的下一个点组成的向量为逆时针旋转。
代码实现

下面是单调链算法的 C++ 实现代码:

// 用于比较两个点的大小
bool cmp(Point a, Point b) {
    return a.x == b.x ? a.y < b.y : a.x < b.x;
}

// 判断三个点的向量关系
int crossProduct(Point A, Point B, Point C) {
    return (B.x - A.x) * (C.y - A.y) - (C.x - A.x) * (B.y - A.y);
}

// 求解凸包
vector<Point> convexHull(vector<Point>& points) {
    int n = points.size();
    if (n <= 1) {
        return points;
    }

    sort(points.begin(), points.end(), cmp);
    vector<Point> ans;
    // 求上凸壳
    for (int i = 0; i < n; ++i) {
        while (ans.size() >= 2 && crossProduct(ans[ans.size() - 2], ans.back(), points[i]) <= 0) {
            ans.pop_back();
        }
        ans.push_back(points[i]);
    }
    // 求下凸壳
    int m = ans.size();
    for (int i = n - 2; i >= 0; --i) {
        while (ans.size() >= m + 1 && crossProduct(ans[ans.size() - 2], ans.back(), points[i]) <= 0) {
            ans.pop_back();
        }
        ans.push_back(points[i]);
    }

    return ans;
}
复杂度分析

单调链算法的时间复杂度为 O(nlogn),其中 n 表示点的数量。这是因为算法的主要开销在于按照 x 坐标排序,以及遍历点集。

总结

单调链算法是一种求解凸包的高效算法,它的时间复杂度为 O(nlogn),并且可以通过栈的数据结构方便地实现。在实际应用中,凸包可以帮助计算和识别出一组点集中的重要特征,如最远点对、最小覆盖圆等。