在计算几何中,凸包(Convex Hull)是一个非常基础且重要的概念。简单来说,给定平面上的一组点,凸包就是能够包围所有这些点的最小凸多边形。想象一下:如果你把每个点都看作一根钉子,然后用一根橡皮筋套住所有钉子并拉紧,那么橡皮筋围成的形状就是这些点的凸包。
本文将带你从零开始,使用C++语言实现两种经典的凸包算法:Graham扫描法和Andrew算法(也称为单调链算法)。即使你是编程小白,也能轻松理解!
凸包具有以下性质:
在实现算法前,我们需要定义点的结构,并掌握判断三点转向的方法——这需要用到向量叉积。
#include <iostream>#include <vector>#include <algorithm>using namespace std;struct Point { long long x, y; Point() {} Point(long long x, long long y) : x(x), y(y) {} bool operator < (const Point& p) const { return x == p.x ? y < p.y : x < p.x; }};// 计算叉积:(B - A) × (C - A)long long cross(const Point& A, const Point& B, const Point& C) { return (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x);} 叉积的结果可以告诉我们三点的转向:
cross > 0:逆时针(左转)cross < 0:顺时针(右转)cross == 0:共线Andrew算法是Graham扫描法的改进版,思路更清晰,代码更简洁。它先对点按x(再按y)排序,然后分别构建下凸壳和上凸壳。
vector<Point> convexHull(vector<Point>& points) { int n = points.size(); if (n <= 1) return points; sort(points.begin(), points.end()); // 按x升序,x相同时按y升序 vector<Point> hull; hull.reserve(n + 1); // 构建下凸壳 for (int i = 0; i < n; ++i) { while (hull.size() >= 2 && cross(hull[hull.size()-2], hull.back(), points[i]) <= 0) { hull.pop_back(); } hull.push_back(points[i]); } // 构建上凸壳 int lower_len = hull.size(); // 下凸壳的长度(包括最右点) for (int i = n - 2; i >= 0; --i) { while (hull.size() > lower_len && cross(hull[hull.size()-2], hull.back(), points[i]) <= 0) { hull.pop_back(); } hull.push_back(points[i]); } // 最后一个点和第一个点重复,去掉 if (hull.size() > 1) hull.pop_back(); return hull;} int main() { vector<Point> points = { {0, 0}, {1, 1}, {2, 0}, {1, 2}, {0, 2}, {2, 2}, {1, 0} }; vector<Point> hull = convexHull(points); cout << "凸包顶点(按顺时针或逆时针顺序):\n"; for (auto& p : hull) { cout << "(" << p.x << ", " << p.y << ")\n"; } return 0;} 相比传统的Graham扫描法,Andrew算法有以下优点:
通过本文,你已经掌握了使用C++凸包算法来求解点集凸包的基本方法。无论是竞赛还是实际工程应用(如碰撞检测、图像处理等),凸包都是一个非常实用的工具。记住关键点:排序 + 叉积判断 + 单调栈维护。
希望这篇教程能帮助你入门计算几何!动手试试吧,修改点集看看凸包如何变化。如果你对Graham扫描法感兴趣,也可以在此基础上进一步探索。
SEO关键词提示:C++凸包算法、计算几何、Andrew算法、Graham扫描法
本文由主机测评网于2025-12-02发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025122059.html