Purpose: Compute the convex hull of a set of 2D points, in O(N log N) time.
Algorithm
- Find the point with the lowest y-coordinate (breaking ties by lowest x) — this is guaranteed to be on the hull. Call it the pivot.
- Sort all other points by polar angle relative to the pivot (counter-clockwise order). Break ties by distance from the pivot.
- Push the pivot and the first sorted point onto a stack.
- For each remaining point in sorted order: while the last three points on the stack (second-to-top, top, current) make a clockwise turn (or straight line), pop the top of the stack.
- Push the current point onto the stack.
- After processing all points, the stack contains the convex hull in counter-clockwise order.
Code
struct Point { long long x, y; };
long long cross(Point O, Point A, Point B) {
return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
}
vector<Point> grahamScan(vector<Point> pts) {
int n = pts.size();
if (n < 3) return pts;
int pivotIdx = 0;
for (int i = 1; i < n; i++)
if (pts[i].y < pts[pivotIdx].y || (pts[i].y == pts[pivotIdx].y && pts[i].x < pts[pivotIdx].x))
pivotIdx = i;
swap(pts[0], pts[pivotIdx]);
Point pivot = pts[0];
sort(pts.begin() + 1, pts.end(), [&](Point a, Point b) {
long long c = cross(pivot, a, b);
if (c != 0) return c > 0;
long long da = (a.x-pivot.x)*(a.x-pivot.x) + (a.y-pivot.y)*(a.y-pivot.y);
long long db = (b.x-pivot.x)*(b.x-pivot.x) + (b.y-pivot.y)*(b.y-pivot.y);
return da < db;
});
vector<Point> hull;
for (Point p : pts) {
while (hull.size() >= 2 && cross(hull[hull.size()-2], hull.back(), p) <= 0)
hull.pop_back();
hull.push_back(p);
}
return hull;
}Paradigm
Greedy (with a Transform-and-Conquer sort step). After sorting points by polar angle (a preprocessing transform), the stack-building pass greedily keeps a point only if it maintains a consistent counter-clockwise turn, permanently discarding points that would create a concave turn.
Complexity
- Time: O(N log N), dominated by the polar-angle sort
- Space: O(N)
Proof of Correctness
Why the pivot is always on the hull: The point with the lowest y-coordinate (breaking ties by lowest x) cannot lie inside the convex hull of the set, since every other point lies on or above the horizontal line through it — meaning no point can “surround” it from below, so it must be a hull vertex.
Why sorting by polar angle and scanning works: After sorting by angle around the pivot, the points are visited in an order consistent with walking counter-clockwise around the eventual hull boundary. Maintaining a stack and popping whenever three consecutive points make a clockwise (or collinear-inward) turn ensures the stack always represents the hull of the points processed so far, because:
- Any point that would create a clockwise turn with the current top two stack points cannot be part of the final convex hull at this stage alongside them — that shape would be non-convex.
- Since points are processed in increasing angular order, once a point is correctly placed relative to all previously seen points, it never needs reconsideration except when a later point invalidates an earlier turn (handled by the popping step).
Invariant: After processing the i-th sorted point, the stack contains exactly the convex hull of the first i points (plus the pivot). This is proven by induction: the base case (first 2-3 points) trivially forms a valid small hull; the inductive step shows that adding the next angularly-sorted point and popping any points that create a clockwise turn restores convexity, since a clockwise turn always indicates the popped point lies strictly inside the hull of the remaining points combined with the new point.
Termination: After all N points are processed, the invariant guarantees the stack holds the full convex hull. ∎
Variants / Use Cases
- Andrew’s Monotone Chain → alternative convex hull algorithm avoiding polar angle sort (sorts by x-coordinate instead), often simpler to implement robustly
- Quickhull → divide-and-conquer convex hull algorithm, average O(N log N) but O(N²) worst case
- 3D convex hull algorithms → generalize the same turn-based idea using orientation tests in 3D
- Collision detection / bounding shapes → convex hulls are used to simplify collision geometry in graphics and robotics
- Farthest pair / diameter of a point set → computed efficiently using rotating calipers on the convex hull