COMPUTER ENGINEER

← BlogDATA STRUCTURES / ALGORITHMSPython example pack ↓

Geometry and numerical algorithms · 42 / 53

Convex hull, sweep lines and robust geometry

Understand → trace → implement → justify

2 min reading · allow extra time for practice

A convex hull is the smallest convex polygon enclosing the points, not a circle. Andrew’s monotone chain sorts points then builds lower and upper chains. A cross product measures orientation; remove the last point when it creates the wrong turn. Each point is pushed and popped at most once, so chain construction is linear. Graham scan uses angular ordering; Jarvis march takes O(nh) for h output vertices.

A wrong sign can change geometric topology. Arbitrary floating-point epsilon is not universally reliable. Avoid integer overflow and use robust orientation predicates or appropriate exact arithmetic for floating inputs. Specify duplicates, collinear input and whether boundary-collinear points should be retained.

Sweep-line methods process ordered events and maintain an active set. Equal-coordinate event ordering and consistent comparisons matter. Voronoi diagrams and Delaunay triangulations model proximity; hulls do not solve every geometric problem. Squared-distance comparison avoids square roots, but not overflow.

A worked trace

For square corners and a centre point, the centre is removed. The <=0 test also removes intermediate collinear boundary points.

Cost and assumptions

Monotone chain: O(n log n) time and O(n) space. Intersection costs depend on events and output size.

Executable example

Run with Python 3. Assertions check a small example; they do not constitute a general correctness proof. Some advanced examples are explicitly small models or reference oracles, not full production implementations.

Python 3
def hull(points):
    points = sorted(set(points))
    if len(points) <= 1: return points
    def cross(a,b,c): return (b[0]-a[0])*(c[1]-a[1])-(b[1]-a[1])*(c[0]-a[0])
    def chain(ps):
        out=[]
        for p in ps:
            while len(out)>1 and cross(out[-2],out[-1],p)<=0: out.pop()
            out.append(p)
        return out
    return chain(points)[:-1]+chain(points[::-1])[:-1]
assert len(hull([(0,0),(1,0),(1,1),(0,1),(.5,.5)]))==4

TEST YOUR UNDERSTANDING

Your turn

What does this implementation return for entirely collinear input?

Reveal the reasoning

Only the two endpoints remain. Retaining every boundary point requires a different turn rule and careful merging.

Take it further

  1. Write down the input contract and the invariant before changing the example.
  2. Add empty, boundary, duplicate and adversarial cases where they are relevant. Compare with a simple oracle.
  3. Derive the cost under the stated model; measure several input sizes and explain discrepancies.

Primary reading & lecture notes

Original explanations in this course; these references provide proofs and further reading. Source links may cover the broader module.

Jeff Erickson · Algorithms ↗
Solve the exercise before moving on.