1. 算法思路:
类似于选择排序,每次找到极角最小的点加入到点集 result
中,具体步骤见 2.2
时间复杂度 :O(n⋅h)
其中 h 是凸包中顶点的数量,因此最坏的情况是 O(n2)。
2. 示例代码:
2.1 import
1 2 3
| import java.util.*; import primitives.Point; import primitives.Polygon;
|
2.2 march算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public static Polygon Jarvis(ArrayList<Point> pointsList) {
ArrayList<Point> points = (ArrayList<Point>)pointsList.clone(); ArrayList<Point> result = new ArrayList<Point>();
Point p0 = getLowestPoint(points); result.add(p0); points.remove(p0);
Point pE = points.get(0); Point candidate; for(int i = 1; i < points.size(); i++) { candidate = points.get(i); if(crossProduct(p0, candidate, pE) < 0) { pE = candidate; } }
Point next = null; Point last = p0; do { next = points.get(0); for(int i = 1; i < points.size(); i++) { candidate = points.get(i); if (crossProduct(last, candidate, next) > 0 || crossProduct(last, candidate, next) == 0 && last.dist(candidate) > last.dist(next)) { next = candidate; } } result.add(next); points.remove(next); last = next; } while(next != pE);
return new Polygon(result); }
|
1. 先找最低点 P0;
2. 对 points
进行遍历,找到极角最大点,即为 凸包的最后一个顶点 PE
,该处为 P9;
3. 再在 points
中找到以点 last
为轴,极角最小的点 next
,若极角相同,则取离 last
最远的;
4. 找到后,将极角最小的点 next
加入点集 result
,同时将 last
赋为 next
;(last
是变化的)
5. 重复进行步骤 3. ~ 4. 的操作,直至找到最后一个顶点 PE
,即 P9 。

points |
result |
last |
next |
P0,P1,P2,P3,P4,P5,P6,P7,P8,P9 |
|
NULL |
NULL |
P1,P2,P3,P4,P5,P6,P7,P8,P9 |
P0 |
P0 |
NULL |
P2,P3,P4,P5,P6,P7,P8,P9 |
P0,P1 |
P0 |
P1 |
P3,P4,P5,P6,P7,P8,P9 |
P0,P1,P2 |
P1 |
P2 |
P3,P4,P6,P7,P8,P9 |
P0,P1,P2,P5 |
P2 |
P5 |
P3,P4,P7,P8,P9 |
P0,P1,P2,P5,P6 |
P5 |
P6 |
P3,P4,P7,P9 |
P0,P1,P2,P5,P6,P8 |
P6 |
P8 |
P3,P4,P7 |
P0,P1,P2,P5,P6,P8,P9 |
P8 |
P9(跳出循环) |
2.3 其他方法
2.3.1 叉积
1 2 3 4 5 6 7 8 9 10
| private static double crossProduct(Point p0, Point p1, Point p2) { return (p1.getX() - p0.getX()) * (p2.getY() - p0.getY()) - (p2.getX() - p0.getX()) * (p1.getY() - p0.getY()); }
private static boolean isLeftTurn(Point p0, Point p1, Point p2) { return (crossProduct(p0, p1, p2) > 0); }
|
P0P1×P0P2

2.3.2 获得最低点
lowest-then-leftmost point(LTL)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private static Point getLowestPoint(ArrayList<Point> points) { Point result = points.get(0);
Point candidate;
for (int i = 1; i < points.size(); i++) { candidate = points.get(i); if (candidate.getY() < result.getY() || candidate.getY() == result.getY() && candidate.getX() < result.getX()) { result = candidate; } } return result; }
|