Convex Hull | Monotone chain algorithm

Given a set of points, the task is to find the convex hull of the given points. The convex hull is the smallest convex polygon that contains all the points.

Examples:

Input: Points[] = {{0, 3}, {2, 2}, {1, 1}, {2, 1}, {3, 0}, {0, 0}, {3, 3}}
Output:
(0, 0)
(3, 0)
(3, 3)
(0, 3)

Approach: Monotone chain algorithm constructs the convex hull in O(n * log(n)) time. We have to sort the points first and then calculate the upper and lower hulls in O(n) time. The points will be sorted with respect to x-coordinates (with respect to y-coordinates in case of a tie in x-coordinates), we will then find the left most point and then try to rotate in clockwise direction and find the next point and then repeat the step until we reach the rightmost point and then again rotate in the clockwise direction and find the lower hull.
Below is the implementation of the above approach:

CPP

 `// C++ implementation of the approach``#include ``#define llu long long int``using` `namespace` `std;` `struct` `Point {` `    ``llu x, y;` `    ``bool` `operator<(Point p)``    ``{``        ``return` `x < p.x || (x == p.x && y < p.y);``    ``}``};` `// Cross product of two vectors OA and OB``// returns positive for counter clockwise``// turn and negative for clockwise turn``llu cross_product(Point O, Point A, Point B)``{``    ``return` `(A.x - O.x) * (B.y - O.y)``           ``- (A.y - O.y) * (B.x - O.x);``}` `// Returns a list of points on the convex hull``// in counter-clockwise order``vector convex_hull(vector A)``{``    ``int` `n = A.size(), k = 0;` `    ``if` `(n <= 3)``        ``return` `A;` `    ``vector ans(2 * n);` `    ``// Sort points lexicographically``    ``sort(A.begin(), A.end());` `    ``// Build lower hull``    ``for` `(``int` `i = 0; i < n; ++i) {` `        ``// If the point at K-1 position is not a part``        ``// of hull as vector from ans[k-2] to ans[k-1]``        ``// and ans[k-2] to A[i] has a clockwise turn``        ``while` `(``            ``k >= 2``            ``&& cross_product(ans[k - 2], ans[k - 1], A[i])``                   ``<= 0)``            ``k--;``        ``ans[k++] = A[i];``    ``}` `    ``// Build upper hull``    ``for` `(``size_t` `i = n - 1, t = k + 1; i > 0; --i) {` `        ``// If the point at K-1 position is not a part``        ``// of hull as vector from ans[k-2] to ans[k-1]``        ``// and ans[k-2] to A[i] has a clockwise turn``        ``while` `(k >= t``               ``&& cross_product(ans[k - 2], ans[k - 1],``                                ``A[i - 1])``                      ``<= 0)``            ``k--;``        ``ans[k++] = A[i - 1];``    ``}` `    ``// Resize the array to desired size``    ``ans.resize(k - 1);` `    ``return` `ans;``}` `// Driver code``int` `main()``{``    ``vector points;` `    ``// Add points``    ``points.push_back({ 0, 3 });``    ``points.push_back({ 2, 2 });``    ``points.push_back({ 1, 1 });``    ``points.push_back({ 2, 1 });``    ``points.push_back({ 3, 0 });``    ``points.push_back({ 0, 0 });``    ``points.push_back({ 3, 3 });` `    ``// Find the convex hull``    ``vector ans = convex_hull(points);` `    ``// Print the convex hull``    ``for` `(``int` `i = 0; i < ans.size(); i++)``        ``cout << ``"("` `<< ans[i].x << ``", "` `<< ans[i].y << ``")"``             ``<< endl;` `    ``return` `0;``}`

Python3

 `class` `Point(``object``):``    ``def` `__init__(``self``, x, y):``        ``self``.x ``=` `x``        ``self``.y ``=` `y` `# A utility function to find next``# to top in a stack`  `def` `nextToTop(S):``    ``a ``=` `S.pop()``    ``b ``=` `S.pop()``    ``S.append(a)``    ``return` `b` `# A utility function to swap two``# points`  `def` `swap(p1, p2):``    ``return` `p2, p1` `# A utility function to return``# square of distance between``# two points`  `def` `distSq(p1, p2):``    ``return` `(p1.x ``-` `p2.x) ``*` `(p1.x ``-` `p2.x) ``+` `(p1.y ``-` `p2.y) ``*` `(p1.y ``-` `p2.y)` `# Prints convex hull of a set of n``# points.`  `def` `convexHull(points, n):` `    ``# There must be at least 3 points``    ``if` `(n < ``3``):``        ``return` `    ``# Initialize Result``    ``hull ``=` `[]` `    ``# Find the leftmost point``    ``l ``=` `0``    ``for` `i ``in` `range``(``1``, n):``        ``if` `(points[i].x < points[l].x):``            ``l ``=` `i` `    ``# Start from leftmost point, keep``    ``# moving counterclockwise until``    ``# reach the start point again``    ``# This loop runs O(h) times where h is``    ``# number of points in result or output.``    ``p ``=` `l``    ``q ``=` `0``    ``while` `(``True``):` `        ``# Add current point to result``        ``hull.append(points[p])` `        ``# Search for a point 'q' such that``        ``# orientation(p, x, q) is counterclockwise``        ``# for all points 'x'. The idea is to keep``        ``# track of last visited most counterclock-``        ``# wise point in q. If any point 'i' is more``        ``# counterclock-wise than q, then update q.``        ``q ``=` `(p ``+` `1``) ``%` `n` `        ``for` `i ``in` `range``(``0``, n):` `            ``# If i is more counterclockwise than``            ``# current q, then update q``            ``if` `(orientation(points[p], points[i], points[q]) ``=``=` `2``):``                ``q ``=` `i` `        ``# Now q is the most counterclockwise with``        ``# respect to p. Set p as q for next iteration,``        ``# so that q is added to result 'hull'``        ``p ``=` `q` `        ``# While we don't come to first point``        ``if` `(p ``=``=` `l):``            ``break` `    ``# Print Result``    ``printHull(hull)` `# A utility function to return square``# of distance between p1 and p2`  `def` `distSq(p1, p2):``    ``return` `(p1.x ``-` `p2.x) ``*` `(p1.x ``-` `p2.x) ``+` `(p1.y ``-` `p2.y) ``*` `(p1.y ``-` `p2.y)` `# To find orientation of ordered triplet (p, q, r).``# The function returns following values``# 0 --> p, q and r are collinear``# 1 --> Clockwise``# 2 --> Counterclockwise`  `def` `orientation(p, q, r):``    ``val ``=` `(q.y ``-` `p.y) ``*` `(r.x ``-` `q.x) ``-` `(q.x ``-` `p.x) ``*` `(r.y ``-` `q.y)` `    ``if` `(val ``=``=` `0``):``        ``return` `0`  `# collinear``    ``elif` `(val > ``0``):``        ``return` `1`   `# clock or wise``    ``else``:``        ``return` `2`   `# counterclock or wise` `# Prints convex hull of a set of n points.`  `def` `printHull(hull):` `    ``print``(``"The points in Convex Hull are:"``)``    ``for` `i ``in` `range``(``len``(hull)):``        ``print``(``"("``, hull[i].x, ``", "``, hull[i].y, ``")"``)`  `# Driver Code``if` `__name__ ``=``=` `"__main__"``:` `    ``points ``=` `[]``    ``points.append(Point(``0``, ``3``))``    ``points.append(Point(``2``, ``2``))``    ``points.append(Point(``1``, ``1``))``    ``points.append(Point(``2``, ``1``))``    ``points.append(Point(``3``, ``0``))``    ``points.append(Point(``0``, ``0``))``    ``points.append(Point(``3``, ``3``))` `    ``n ``=` `len``(points)``    ``convexHull(points, n)` `    ``# This code is contributed by ishankhandelwals.`

Javascript

 `// JS implementation of the approach``function` `Point(x, y) {``    ``this``.x = x;``    ``this``.y = y;``}` `function` `crossProduct(O, A, B) {``    ``return` `(A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);``}` `function` `convexHull(A) {``    ``let n = A.length;``    ``let k = 0;` `    ``if` `(n <= 3)``        ``return` `A;` `    ``let ans = ``new` `Array(2 * n);` `    ``// Sort points lexicographically``    ``A.sort((a, b) => {``        ``return` `a.x < b.x || (a.x == b.x && a.y < b.y);``    ``});` `    ``// Build lower hull``    ``for` `(let i = 0; i < n; ++i) {` `        ``// If the point at K-1 position is not a part``        ``// of hull as vector from ans[k-2] to ans[k-1] ``        ``// and ans[k-2] to A[i] has a clockwise turn``        ``while` `(k >= 2 && crossProduct(ans[k - 2], ans[k - 1], A[i]) <= 0)``            ``k--;``        ``ans[k++] = A[i];``    ``}` `    ``// Build upper hull``    ``for` `(let i = n - 1, t = k + 1; i > 0; --i) {` `        ``// If the point at K-1 position is not a part``        ``// of hull as vector from ans[k-2] to ans[k-1] ``        ``// and ans[k-2] to A[i] has a clockwise turn``        ``while` `(k >= t && crossProduct(ans[k - 2], ans[k - 1], A[i - 1]) <= 0)``            ``k--;``        ``ans[k++] = A[i - 1];``    ``}` `    ``// Resize the array to desired size``    ``ans.length = k - 1;` `    ``return` `ans;``}` `// Driver code``let points = [];` `// Add points``points.push(``new` `Point(0, 3));``points.push(``new` `Point(2, 2));``points.push(``new` `Point(1, 1));``points.push(``new` `Point(2, 1));``points.push(``new` `Point(3, 0));``points.push(``new` `Point(0, 0));``points.push(``new` `Point(3, 3));` `// Find the convex hull``let ans = convexHull(points);` `// Print the convex hull``for` `(let i = 0; i < ans.length; i++)``    ``console.log(``"("` `+ ans[i].x + ``", "` `+ ans[i].y + ``")"``);``    ` `    ``// This code is contributed by ishankhandelwals.`

C#

 `using` `System;``using` `System.Collections.Generic;``using` `System.Collections;``using` `System.Linq;` `class` `Point {``    ``public` `int` `x;``    ``public` `int` `y;` `    ``public` `Point(``int` `x, ``int` `y)``    ``{``        ``this``.x = x;``        ``this``.y = y;``    ``}``}` `class` `HelloWorld {` `    ``// A utility function to return square``    ``// of distance between p1 and p2``    ``public` `static` `int` `distSq(Point p1, Point p2)``    ``{``        ``return` `(p1.x - p2.x) * (p1.x - p2.x)``            ``+ (p1.y - p2.y) * (p1.y - p2.y);``    ``}` `    ``// To find orientation of ordered triplet (p, q, r).``    ``// The function returns following values``    ``// 0 --> p, q and r are collinear``    ``// 1 --> Clockwise``    ``// 2 --> Counterclockwise``    ``public` `static` `int` `orientation(Point p, Point q, Point r)``    ``{``        ``int` `val = (q.y - p.y) * (r.x - q.x)``                  ``- (q.x - p.x) * (r.y - q.y);` `        ``if` `(val == 0)``            ``return` `0;``        ``else` `if` `(val > 0)``            ``return` `1;``        ``else``            ``return` `2;``    ``}` `    ``// Prints convex hull of a set of n points.``    ``public` `static` `void` `printHull(List hull)``    ``{` `        ``Console.WriteLine(``"The points in Convex Hull are:"``);``        ``for` `(``int` `i = 0; i < hull.Count; i++) {``            ``Console.WriteLine(``"("` `+ hull[i].x + ``", "``                              ``+ hull[i].y + ``")"``);``        ``}``    ``}` `    ``// Prints convex hull of a set of n``    ``// points.``    ``public` `static` `void` `convexHull(List points, ``int` `n)``    ``{` `        ``// There must be at least 3 points``        ``if` `(n < 3) {``            ``return``;``        ``}` `        ``// Initialize Result``        ``List hull = ``new` `List();` `        ``// Find the leftmost point``        ``int` `l = 0;``        ``for` `(``int` `i = 1; i < n; i++) {``            ``if` `(points[i].x < points[l].x) {``                ``l = i;``            ``}``        ``}` `        ``// Start from leftmost point, keep``        ``// moving counterclockwise until``        ``// reach the start point again``        ``// This loop runs O(h) times where h is``        ``// number of points in result or output.``        ``int` `p = l;``        ``int` `q = 0;``        ``while` `(``true``) {` `            ``// Add current point to result``            ``hull.Add(points[p]);` `            ``// Search for a point 'q' such that``            ``// orientation(p, x, q) is counterclockwise``            ``// for all points 'x'. The idea is to keep``            ``// track of last visited most counterclock-``            ``// wise point in q. If any point 'i' is more``            ``// counterclock-wise than q, then update q.``            ``q = (p + 1) % n;` `            ``for` `(``int` `i = 0; i < n; i++) {` `                ``// If i is more counterclockwise than``                ``// current q, then update q``                ``if` `(orientation(points[p], points[i],``                                ``points[q])``                    ``== 2) {``                    ``q = i;``                ``}``            ``}` `            ``// Now q is the most counterclockwise with``            ``// respect to p. Set p as q for next iteration,``            ``// so that q is added to result 'hull'``            ``p = q;` `            ``// While we don't come to first point``            ``if` `(p == l) {``                ``break``;``            ``}``        ``}` `        ``// Print Result``        ``printHull(hull);``    ``}` `    ``static` `void` `Main()``    ``{``        ``List points = ``new` `List();` `        ``points.Add(``new` `Point(0, 3));``        ``points.Add(``new` `Point(2, 2));``        ``points.Add(``new` `Point(1, 1));``        ``points.Add(``new` `Point(2, 1));``        ``points.Add(``new` `Point(3, 0));``        ``points.Add(``new` `Point(0, 0));``        ``points.Add(``new` `Point(3, 3));` `        ``int` `n = points.Count;``        ``convexHull(points, n);``    ``}``}` `// The code is contributed by Nidhi goel.`

Java

 `import` `java.util.*;` `class` `Point ``implements` `Comparable {``    ``long` `x, y;` `    ``public` `Point(``long` `x, ``long` `y)``    ``{``        ``this``.x = x;``        ``this``.y = y;``    ``}``    ``// Implement compareTo method for sorting``    ``@Override` `public` `int` `compareTo(Point p)``    ``{``        ``return` `Long.compare(x, p.x) != ``0``            ``? Long.compare(x, p.x)``            ``: Long.compare(y, p.y);``    ``}``}` `public` `class` `ConvexHull {``    ``// Cross product of two vectors OA and OB``    ``// returns positive for counter clockwise``    ``// turn and negative for clockwise turn``    ``static` `long` `crossProduct(Point O, Point A, Point B)``    ``{``        ``return` `(A.x - O.x) * (B.y - O.y)``            ``- (A.y - O.y) * (B.x - O.x);``    ``}``    ``// Returns a list of points on the convex hull``    ``// in counter-clockwise order``    ``static` `List convexHull(List A)``    ``{``        ``int` `n = A.size(), k = ``0``;` `        ``if` `(n <= ``3``)``            ``return` `A;` `        ``List ans = ``new` `ArrayList<>(``2` `* n);` `        ``// Sort points lexicographically``        ``Collections.sort(A);` `        ``// Build lower hull``        ``for` `(``int` `i = ``0``; i < n; ++i) {``            ``// If the point at K-1 position is not a part``            ``// of hull as vector from ans[k-2] to ans[k-1]``            ``// and ans[k-2] to A[i] has a clockwise turn``            ``while` `(k >= ``2``                   ``&& crossProduct(ans.get(k - ``2``),``                                   ``ans.get(k - ``1``), A.get(i))``                          ``<= ``0``)``                ``ans.remove(--k);``            ``ans.add(A.get(i));``            ``k++;``        ``}` `        ``// Build upper hull``        ``for` `(``int` `i = n - ``2``, t = k; i >= ``0``; --i) {` `            ``// If the point at K-1 position is not a part``            ``// of hull as vector from ans[k-2] to ans[k-1]``            ``// and ans[k-2] to A[i] has a clockwise turn``            ``while` `(k > t``                   ``&& crossProduct(ans.get(k - ``2``),``                                   ``ans.get(k - ``1``), A.get(i))``                          ``<= ``0``)``                ``ans.remove(--k);``            ``ans.add(A.get(i));``            ``k++;``        ``}` `        ``// Resize the array to desired size``        ``ans.remove(ans.size() - ``1``);` `        ``return` `ans;``    ``}` `    ``// Driver code``    ``public` `static` `void` `main(String[] args)``    ``{``        ``List points = ``new` `ArrayList<>();` `        ``// Add points``        ``points.add(``new` `Point(``0``, ``3``));``        ``points.add(``new` `Point(``2``, ``2``));``        ``points.add(``new` `Point(``1``, ``1``));``        ``points.add(``new` `Point(``2``, ``1``));``        ``points.add(``new` `Point(``3``, ``0``));``        ``points.add(``new` `Point(``0``, ``0``));``        ``points.add(``new` `Point(``3``, ``3``));` `        ``// Find the convex hull``        ``List ans = convexHull(points);` `        ``// Print the convex hull``        ``for` `(Point p : ans)``            ``System.out.println(``"("` `+ p.x + ``", "` `+ p.y``                               ``+ ``")"``);``    ``}``}`

Output:
```(0, 0)
(3, 0)
(3, 3)
(0, 3)```

Previous
Next