最痛苦的一周——第三周作业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();
    }
}

posted @ 2018-03-05 09:34  新月的力量_141  阅读(691)  评论(0编辑  收藏  举报