Skip to content

Commit 5c18b74

Browse files
committed
Bug-fix : fixed the loss of order due to usage of Hashset in ConvexHull code
1 parent 8ddde38 commit 5c18b74

File tree

1 file changed

+38
-89
lines changed

1 file changed

+38
-89
lines changed
Lines changed: 38 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,66 @@
11
package com.thealgorithms.geometry;
22

33
import java.util.ArrayList;
4-
import java.util.Collection;
54
import java.util.Collections;
6-
import java.util.Comparator;
7-
import java.util.HashSet;
85
import java.util.List;
9-
import java.util.Set;
10-
import java.util.TreeSet;
116

127
/**
138
* A class providing algorithms to compute the convex hull of a set of points
14-
* using brute-force and recursive methods.
9+
* using the recursive (Divide-and-Conquer) method.
1510
*
1611
* Convex hull: The smallest convex polygon that contains all the given points.
1712
*
18-
* Algorithms provided:
19-
* 1. Brute-Force Method
20-
* 2. Recursive (Divide-and-Conquer) Method
21-
*
22-
* @author Hardvan
13+
* This implementation ensures that the points on the hull are returned
14+
* in counter-clockwise order, which is required by algorithms like
15+
* Rotating Calipers.
2316
*/
2417
public final class ConvexHull {
2518
private ConvexHull() {
2619
}
2720

28-
private static boolean checkPointOrientation(Point i, Point j, Point k) {
29-
int detK = Point.orientation(i, j, k);
30-
if (detK > 0) {
31-
return true; // pointsLeftOfIJ
32-
} else if (detK < 0) {
33-
return false; // pointsRightOfIJ
34-
} else {
35-
return k.compareTo(i) >= 0 && k.compareTo(j) <= 0;
21+
public static List<Point> convexHullRecursive(List<Point> points) {
22+
if (points.size() <= 1) {
23+
return new ArrayList<>(points);
3624
}
37-
}
38-
39-
public static List<Point> convexHullBruteForce(List<Point> points) {
40-
Set<Point> convexSet = new TreeSet<>(Comparator.naturalOrder());
41-
42-
for (int i = 0; i < points.size() - 1; i++) {
43-
for (int j = i + 1; j < points.size(); j++) {
44-
boolean allPointsOnOneSide = true;
45-
boolean leftSide = checkPointOrientation(points.get(i), points.get(j), points.get((i + 1) % points.size()));
4625

47-
for (int k = 0; k < points.size(); k++) {
48-
if (k != i && k != j && checkPointOrientation(points.get(i), points.get(j), points.get(k)) != leftSide) {
49-
allPointsOnOneSide = false;
50-
break;
51-
}
52-
}
53-
54-
if (allPointsOnOneSide) {
55-
convexSet.add(points.get(i));
56-
convexSet.add(points.get(j));
57-
}
26+
// Sort points by x (then by y)
27+
List<Point> sorted = new ArrayList<>(points);
28+
Collections.sort(sorted);
29+
30+
List<Point> lower = new ArrayList<>();
31+
for (Point p : sorted) {
32+
while (lower.size() >= 2
33+
&& Point.orientation(
34+
lower.get(lower.size() - 2),
35+
lower.get(lower.size() - 1),
36+
p)
37+
<= 0) {
38+
lower.remove(lower.size() - 1);
5839
}
40+
lower.add(p);
5941
}
6042

61-
return new ArrayList<>(convexSet);
62-
}
63-
64-
public static List<Point> convexHullRecursive(List<Point> points) {
65-
Collections.sort(points);
66-
Set<Point> convexSet = new HashSet<>();
67-
Point leftMostPoint = points.get(0);
68-
Point rightMostPoint = points.get(points.size() - 1);
69-
70-
convexSet.add(leftMostPoint);
71-
convexSet.add(rightMostPoint);
72-
73-
List<Point> upperHull = new ArrayList<>();
74-
List<Point> lowerHull = new ArrayList<>();
75-
76-
for (int i = 1; i < points.size() - 1; i++) {
77-
int det = Point.orientation(leftMostPoint, rightMostPoint, points.get(i));
78-
if (det > 0) {
79-
upperHull.add(points.get(i));
80-
} else if (det < 0) {
81-
lowerHull.add(points.get(i));
43+
List<Point> upper = new ArrayList<>();
44+
for (int i = sorted.size() - 1; i >= 0; i--) {
45+
Point p = sorted.get(i);
46+
while (upper.size() >= 2
47+
&& Point.orientation(
48+
upper.get(upper.size() - 2),
49+
upper.get(upper.size() - 1),
50+
p)
51+
<= 0) {
52+
upper.remove(upper.size() - 1);
8253
}
54+
upper.add(p);
8355
}
8456

85-
constructHull(upperHull, leftMostPoint, rightMostPoint, convexSet);
86-
constructHull(lowerHull, rightMostPoint, leftMostPoint, convexSet);
87-
88-
List<Point> result = new ArrayList<>(convexSet);
89-
Collections.sort(result);
90-
return result;
91-
}
57+
// Remove last point of each list (duplicate with start of other list)
58+
lower.remove(lower.size() - 1);
59+
upper.remove(upper.size() - 1);
9260

93-
private static void constructHull(Collection<Point> points, Point left, Point right, Set<Point> convexSet) {
94-
if (!points.isEmpty()) {
95-
Point extremePoint = null;
96-
int extremePointDistance = Integer.MIN_VALUE;
97-
List<Point> candidatePoints = new ArrayList<>();
61+
List<Point> hull = new ArrayList<>(lower);
62+
hull.addAll(upper);
9863

99-
for (Point p : points) {
100-
int det = Point.orientation(left, right, p);
101-
if (det > 0) {
102-
candidatePoints.add(p);
103-
if (det > extremePointDistance) {
104-
extremePointDistance = det;
105-
extremePoint = p;
106-
}
107-
}
108-
}
109-
110-
if (extremePoint != null) {
111-
constructHull(candidatePoints, left, extremePoint, convexSet);
112-
convexSet.add(extremePoint);
113-
constructHull(candidatePoints, extremePoint, right, convexSet);
114-
}
115-
}
64+
return hull;
11665
}
11766
}

0 commit comments

Comments
 (0)