Statement
Problem
Given points P={Pi}i=1n⊂E2, find the smallest convex polygon Conv(P) such that P⊆Conv(P).
Solution
First we pick a reference point Q0, in Graham's scan we pick the Pi with the smallest y coordinate, then the smallest x coordinate in case of a tie.
Then, we can treat each Pi∈P as a vector starting at the origin, and compute its angle θ with respect to Q0.
θi=arccos[∥Pi∥∥Q0∥Pi⋅Q0].
We need not compute the actual angle θ; any function which is monotonically increasing over [0,π]. Incidentally, the cosine of the angle satisfies this property, hence we can let θ=P^i⋅Q^0.
Let Conv(P) be the empty set, and Q be the set P ordered by θi, let ties be sorted by the L2 from the centroid of P.
Next, we can iterate through each point Qi of Q.
In each iteration:
- If Conv(P) has fewer than two points, then
- insert Qi to the end of the array and skip to next iteration.
- Check if the triangle formed by Qi and the last two points of Conv(P) has positive area (i.e. points turn in anticlockwise direction)
- If so, add Qi to the end of Conv(P).
- Otherwise, remove the last element of Conv(P), and repeat above step until Qi can be inserted.
Finally, return Conv(P) which is the set containing the points of the convex hull.
Algorithm
Convex Hull (Graham Scan)
- # Input: Set of points P={Pi}i=0n−1 in arbitrary order
- function ConvexHull(P, Pc)
- Q0 ← argminPiPi[y] # Pick Pi with smallest y coordinate.
- Q ← P sorted by θi=angle(Q0,Pi)
- Conv(P) ← ∅
-
- for all Qi in Q do
- if ∥Conv(P)∥≤2 then
- Conv(P) ← Conv(P)∪{Qi}
- continue
-
- m ← ∥Conv(P)∥
- while true
triangle_area
← area(△QiConv(P)m−2Conv(P)m−1)
- if
triangle_area
>0 then
- Conv(P) ← Conv(P)∪{Qi}
- break
-
- Conv(P) ← Conv(P)∖{Conv(P)m−1}
-
- return Conv(P)
Complexity
- Finding Q0 and compuing the angles requires a single traversal of P taking O(n) time.
- Sorting takes O(nlogn) time.
- Inserting into Conv(P) takes O(n) time.
- We iterate through each Qi∈Q once
- If we cannot insert the point, we must backtrack by removing elements from Conv(P), at worst this inner loop is run n−1 times in total, over all Qi, which is O(n)
Therefore, this algorithm takes O(nlogn) time.