《算法》BEYOND 部分程序 part 3

▶ 书中第六章部分程序,加上自己补充的代码,包括 Graham 扫描生成凸包,计算最远点对

● Graham 扫描生成凸包

 1 package package01;
 2 
 3 import java.util.Arrays;
 4 import edu.princeton.cs.algs4.StdIn;
 5 import edu.princeton.cs.algs4.StdOut;
 6 import edu.princeton.cs.algs4.Point2D;
 7 import edu.princeton.cs.algs4.Stack;
 8 
 9 public class class01
10 {
11     private Stack<Point2D> hull = new Stack<Point2D>();
12 
13     public class01(Point2D[] points)
14     {
15         if (points == null || points.length == 0)
16             throw new IllegalArgumentException("argument is null");
17         int n = points.length;
18         Point2D[] a = new Point2D[n];
19         for (int i = 0; i < n; i++)
20             a[i] = points[i];
21 
22         Arrays.sort(a);                             // Y 坐标升序排序,等值的按 X 坐标升序排序,保证 a[0] 为最下最左,a[1] 为
23         Arrays.sort(a, 1, n, a[0].polarOrder());    // 以 a[0] 为原点,幅角升序排序
24         hull.push(a[0]);                            // 第一个点
25         int k1;                                     // 找到下一个相异点
26         for (k1 = 1; k1 < n; k1++)
27         {
28             if (!a[0].equals(a[k1]))
29                 break;
30         }
31         if (k1 == n)
32             return;
33         int k2;                                     // 找到下一个非共线点
34         for (k2 = k1 + 1; k2 < n; k2++)
35         {
36             if (Point2D.ccw(a[0], a[k1], a[k2]) != 0)
37                 break;
38         }
39         hull.push(a[k2 - 1]);                       // a[k2-1] 是与 a[0],a[k1] 共线的最后一个点(也可以先压 a[k1] 然后跳过 a[k2-1])
40         for (int i = k2; i < n; i++)
41         {
42             Point2D top = hull.pop();
43             for (; Point2D.ccw(hull.peek(), top, a[i]) <= 0; top = hull.pop()); // 倒数第 2 点、倒数第 1 点和当前点计算三角形面积,逆时针方向为正
44                                                                                 // 吐栈吐到这 3 点的面积为正为止,压入倒数第 2 点当前点
45             hull.push(top);
46             hull.push(a[i]);
47         }
48         assert isConvex();
49     }
50 
51     public Iterable<Point2D> hull()                 // 得到凸包的迭代器
52     {
53         Stack<Point2D> s = new Stack<Point2D>();
54         for (Point2D p : hull)
55             s.push(p);
56         return s;
57     }
58 
59     private boolean isConvex()                      // 检查凸性
60     {
61         int n = hull.size();
62         if (n <= 2) return true;
63 
64         Point2D[] points = new Point2D[n];
65         int k = 0;
66         for (Point2D p : hull())
67             points[k++] = p;
68 
69         for (int i = 0; i < n; i++)
70         {
71             if (Point2D.ccw(points[i], points[(i + 1) % n], points[(i + 2) % n]) <= 0)
72                 return false;
73         }
74         return true;
75     }
76 
77     public static void main(String[] args)
78     {
79         int n = StdIn.readInt();
80         Point2D[] points = new Point2D[n];
81         for (int i = 0; i < n; i++)
82         {
83             int x = StdIn.readInt(), y = StdIn.readInt();
84             points[i] = new Point2D(x, y);
85         }
86         class01 graham = new class01(points);
87         for (Point2D p : graham.hull())
88             StdOut.println(p);
89     }
90 }

● 计算最远点对

 1 package package01;
 2 
 3 import edu.princeton.cs.algs4.StdIn;
 4 import edu.princeton.cs.algs4.StdOut;
 5 import edu.princeton.cs.algs4.Point2D;
 6 import edu.princeton.cs.algs4.GrahamScan;
 7 
 8 public class class01
 9 {
10     private Point2D best1, best2;
11     private double bestDistanceSquared = Double.NEGATIVE_INFINITY;  // 当前最远点对距离的平方
12 
13     public class01(Point2D[] points)
14     {
15         if (points == null || points.length <= 1)
16             throw new IllegalArgumentException("constructor argument is null");
17 
18         GrahamScan graham = new GrahamScan(points);
19 
20         int m = 0;// 凸包点数
21         for (Point2D p : graham.hull())
22             m++;
23         Point2D[] hull = new Point2D[m + 1];                        // 凸包顶点放入 a[1] ~ a[m]
24         m = 1;
25         for (Point2D p : graham.hull())
26             hull[m++] = p;
27         m--;                                                        // m 等于凸包顶点数
28 
29         if (m == 1) // 所有点都相同
30             return;
31         if (m == 2) // 所有点共线
32         {
33             best1 = hull[1];
34             best2 = hull[2];
35             bestDistanceSquared = best1.distanceSquaredTo(best2);
36             return;
37         }
38 
39         int k = 2;
40         for (; Point2D.area2(hull[m], hull[1], hull[k + 1]) > Point2D.area2(hull[m], hull[1], hull[k]); k++);   // a[k] 是距离直线 a[1]a[m] 最远的点
41 
42         int j = k;
43         for (int i = 1; i <= k && j <= m; i++)                      // j 搜索后半部分,i 搜索前半部分
44         {
45             update(hull[i], hull[j]);                               // i 挪动一位,检查 a[i] 和 a[j] 距离是否更大
46             for (j++; (j <= m) && Point2D.area2(hull[i], hull[i + 1], hull[j]) > Point2D.area2(hull[i], hull[i + 1], hull[j - 1]); j++) 
47                                                                     // j 挪动保持 a[j] 远离直线 a[i]a[i+1]
48                 update(hull[i], hull[j]);
49         }
50     }
51 
52     private void update(Point2D x, Point2D y)
53     {
54         double distanceSquared = x.distanceSquaredTo(y);            
55         if (distanceSquared > bestDistanceSquared)
56         {
57             best1 = x;
58             best2 = y;
59             bestDistanceSquared = distanceSquared;
60         }
61     }
62 
63     public Point2D either()
64     {
65         return best1;
66     }
67 
68     public Point2D other()
69     {
70         return best2;
71     }
72 
73     public double distance()
74     {
75         return Math.sqrt(bestDistanceSquared);
76     }
77 
78     public static void main(String[] args)
79     {
80         int n = StdIn.readInt();
81         Point2D[] points = new Point2D[n];
82         for (int i = 0; i < n; i++)
83         {
84             int x = StdIn.readInt(), y = StdIn.readInt();
85             points[i] = new Point2D(x, y);
86         }
87         class01 farthest = new class01(points);
88         StdOut.println(farthest.distance() + " from " + farthest.either() + " to " + farthest.other());
89     }
90 }
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/10115990.html