Programming Assignment 3: Collinear Points

Coursera:Programming Assignment 3: Pattern Recognition

The problem. Given a set of N distinct points in the plane, draw every (maximal) line segment that connects a subset of 4 or more of the points.

Points and lines

问题是给出N个不同的点,找出并画出4个以上给出的点连接成的直线。

问题要求用Brute force直接遍历找出4个点连成的直线,再用应用排序算法的Fast算法找出4个以上的点连成的直线。

作为开始,给出Point类的代码。

import java.util.Comparator;

public class Point implements Comparable<Point> {

    //实现comparabor接口使用slope作为键值进行比较
    private final class SlopeOrder implements Comparator<Point> {
        
        public int compare(Point v, Point w) {
            
            if (Point.this.slopeTo(v) > Point.this.slopeTo(w))
                return 1;
            else if (Point.this.slopeTo(v) < Point.this.slopeTo(w))
                return -1;
            else 
                return 0;
        }
    }
    
    // compare points by slope
    public final Comparator<Point> SLOPE_ORDER = new SlopeOrder();
    
    private final int x;                              // x coordinate
    private final int y;                              // y coordinate

    // create the point (x, y)
    public Point(int x, int y) {
        /* DO NOT MODIFY */
        this.x = x;
        this.y = y;
    }

    // plot this point to standard drawing
    public void draw() {
        /* DO NOT MODIFY */
        StdDraw.point(x, y);
    }

    // draw line between this point and that point to standard drawing
    public void drawTo(Point that) {
        /* DO NOT MODIFY */
        StdDraw.line(this.x, this.y, that.x, that.y);
    }

    // slope between this point and that point
    public double slopeTo(Point that) {

        double slope;
        if (this.x == that.x && this.y == that.y)
            slope = Double.NEGATIVE_INFINITY;
        else if (this.x == that.x)
            slope = Double.POSITIVE_INFINITY;
        else if (this.y == that.y)
            slope = 0;
        else 
            slope = ((double)(this.y - that.y)) / (this.x - that.x);
        return slope;
    }

    // is this point lexicographically smaller than that one?
    // comparing y-coordinates and breaking ties by x-coordinates
    public int compareTo(Point that) {

        if (this.y > that.y || (this.y == that.y && this.x > that.x))
            return 1;
        else if (this.y < that.y || (this.y == that.y && this.x < that.x))
            return -1;
        else
            return 0;
    }

    // return string representation of this point
    public String toString() {
        /* DO NOT MODIFY */
        return "(" + x + ", " + y + ")";
    }

    // unit test
    public static void main(String[] args) {
        /* YOUR CODE HERE */
    }
}

Point类按照问题要求实现。其中实现Comparator接口的内部类可以使排序算法以不同的键值进行排序。

首先Point类需声明一个SlopeOrder的共有实例变量SLOPE_ORDER,并在实现Comparator的内部类中实现compare方法,这样排序算法只要将第二个参数接收Comparator的对象,在方法中排序时调用该对象的compare方法即可按对象对应键值进行排序。Point类实现了SlopeOrder内部类,这样Fast方法可以利用调用的点this与其他两个点v,w的对应斜率进行排序,系统排序算法有接收comparator对象的对应排序算法,所以调用Arrays.sort即可,这样可以将Brute force方法的运行时间级N^4提高到Fast方法的N^2logN。

下面是Fast类的关键代码

LinkedList<Point> pointList = new LinkedList<Point>();
        for (int i = 0; i < N; i++) {
            //每次slope排序会将i当前对应的点排在第一,所以只需比较points[0]与points中
            //其他元素所成斜率是否相等
            Arrays.sort(points);
            Arrays.sort(points, points[i].SLOPE_ORDER); //以slope作为键值进行排序
            
            for (int j = 0; j < N-1; j++) {
                
                pointList.add(points[j]);
                while (j+1 < N && points[0].slopeTo(points[j]) 
                        == points[0].slopeTo(points[j+1])) {
                    
                    pointList.add(points[++j]);
                    
                }
                //只输出按compareTo排序的点,所以顺序不用但处于同一直线个数相同的只输出一次
                if (pointList.size() >= 3 && points[0].compareTo(pointList.get(0)) < 0) {
                    
                    StdOut.print(points[0].toString());
                    for (int k = 0; k < pointList.size(); k++)
                        StdOut.print(" -> " + pointList.get(k).toString());
                        
                    StdOut.println();
                    points[0].drawTo(pointList.get(pointList.size() - 1));
                }
                pointList.clear();
            }
        }

 

posted @ 2014-09-28 13:17  cnu4  阅读(343)  评论(0)    收藏  举报