最痛苦的一周——第三周作业Collinear
这个作业已经有点儿久远了,但是给我留下了很深的印象。这五周的作业中,就这个最困难了。自己真的花了两天时间在这次作业上面。最后解题思路还是在Coursera讨论上看到的。
brute-force解法就不多说了,但还是踩了一些坑。
重点在FastCollinear的实现,回过头来发现只有一百多行代码真的不敢置信。这次作业是对sort的应用。按每个点和其它点形成的斜率,然后排序。所以如果有四点在一个线上,非常容易寻找。但是最困的是找出重复的线段和子线段。在论坛找到的思路是遍历按斜率排序好的队列,将几个相同的放到Stack中,将保存到Stack中的同线点排序,于是就找出并保存了最大线段。
还有一个坑是,因为循环写法的原因,这个点的判断在下一次加入到队列中。所以最后一个点没有加入进去。而垂直的线斜率最大,正好排在最后。因此所有垂直的线丢没有找出来。
BruteCollinearPoints.java
···
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;
import java.util.Arrays;
public class BruteCollinearPoints {
private LineSegment[] segments;
private int endpoint;
private int nsegments;
public BruteCollinearPoints(Point[] pointss) {
if(pointss == null)
throw new IllegalArgumentException();
for(int i=0; i<pointss.length; i++) {
if(pointss[i] == null)
throw new IllegalArgumentException();
}
for(int i=0; i<pointss.length; i++) {
for(int j=0; j<pointss.length; j++) {
if(i == j)
continue;
if(pointss[i].slopeTo(pointss[j]) == Double.NEGATIVE_INFINITY)
throw new IllegalArgumentException();
}
}
Point[] points = new Point[pointss.length];
for(int i=0;i<points.length;i++) {
points[i] = pointss[i];
}
Arrays.sort(points);
segments = new LineSegment[points.length];
endpoint = points.length - 1;
try {
outer:
for(int p=0; p<points.length; p++) {
for(int q=endpoint; q>p; q--) {
double pq = points[p].slopeTo(points[q]);
for(int r=q-1; r>p; r--) {
double qr = points[q].slopeTo(points[r]);
if(qr == pq)
for(int s=r-1; s>p; s--) {
double rs = points[r].slopeTo(points[s]);
if(qr == rs) {
segments[nsegments++] = new LineSegment(points[p], points[q]);
//continue outer;
}
}
}
}
}
} catch (NullPointerException e) {
throw new IllegalArgumentException();
}
}
public int numberOfSegments() {
return nsegments;
}
public LineSegment[] segments() {
LineSegment[] lineSegements = new LineSegment[nsegments];
for(int i=0; i<nsegments; i++) {
lineSegements[i] = segments[i];
}
return lineSegements;
}
public static void main(String[] args) {
// read the n points from a file
In in = new In(args[0]);
int n = in.readInt();
Point[] points = new Point[n];
for (int i = 0; i < n; i++) {
int x = in.readInt();
int y = in.readInt();
points[i] = new Point(x, y);
}
// draw the points
StdDraw.enableDoubleBuffering();
StdDraw.setXscale(0, 32768);
StdDraw.setYscale(0, 32768);
for (Point p : points) {
p.draw();
}
StdDraw.show();
// print and draw the line segments
BruteCollinearPoints collinear = new BruteCollinearPoints(points);
for (LineSegment segment : collinear.segments()) {
StdOut.println(segment);
segment.draw();
}
StdDraw.show();
}
}
···
FastCollinearPoints.java
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;
import java.util.Arrays;
public class BruteCollinearPoints {
private LineSegment[] segments;
private int endpoint;
private int nsegments;
public BruteCollinearPoints(Point[] pointss) {
if(pointss == null)
throw new IllegalArgumentException();
for(int i=0; i<pointss.length; i++) {
if(pointss[i] == null)
throw new IllegalArgumentException();
}
for(int i=0; i<pointss.length; i++) {
for(int j=0; j<pointss.length; j++) {
if(i == j)
continue;
if(pointss[i].slopeTo(pointss[j]) == Double.NEGATIVE_INFINITY)
throw new IllegalArgumentException();
}
}
Point[] points = new Point[pointss.length];
for(int i=0;i<points.length;i++) {
points[i] = pointss[i];
}
Arrays.sort(points);
segments = new LineSegment[points.length];
endpoint = points.length - 1;
try {
outer:
for(int p=0; p<points.length; p++) {
for(int q=endpoint; q>p; q--) {
double pq = points[p].slopeTo(points[q]);
for(int r=q-1; r>p; r--) {
double qr = points[q].slopeTo(points[r]);
if(qr == pq)
for(int s=r-1; s>p; s--) {
double rs = points[r].slopeTo(points[s]);
if(qr == rs) {
segments[nsegments++] = new LineSegment(points[p], points[q]);
//continue outer;
}
}
}
}
}
} catch (NullPointerException e) {
throw new IllegalArgumentException();
}
}
public int numberOfSegments() {
return nsegments;
}
public LineSegment[] segments() {
LineSegment[] lineSegements = new LineSegment[nsegments];
for(int i=0; i<nsegments; i++) {
lineSegements[i] = segments[i];
}
return lineSegements;
}
public static void main(String[] args) {
// read the n points from a file
In in = new In(args[0]);
int n = in.readInt();
Point[] points = new Point[n];
for (int i = 0; i < n; i++) {
int x = in.readInt();
int y = in.readInt();
points[i] = new Point(x, y);
}
// draw the points
StdDraw.enableDoubleBuffering();
StdDraw.setXscale(0, 32768);
StdDraw.setYscale(0, 32768);
for (Point p : points) {
p.draw();
}
StdDraw.show();
// print and draw the line segments
BruteCollinearPoints collinear = new BruteCollinearPoints(points);
for (LineSegment segment : collinear.segments()) {
StdOut.println(segment);
segment.draw();
}
StdDraw.show();
}
}