【Coursera】编程题 Collinear Points

来源:互联网 发布:2016网络神曲排行榜 编辑:程序博客网 时间:2024/04/20 01:30

题目概述:http://coursera.cs.princeton.edu/algs4/assignments/collinear.html

Point类和暴力算法(O(n^4))都很简单,就不写了。

写一个把复杂度降到n^2lg(n)的算法。

感觉写出来的东西很混乱。。


import java.util.ArrayList;import java.util.Arrays;import edu.princeton.cs.algs4.Quick3way;import edu.princeton.cs.algs4.StdDraw;import edu.princeton.cs.algs4.StdIn;import edu.princeton.cs.algs4.StdOut;public class FastCollinearPoints {    private int num = 0;    // number of lines    private ArrayList<LineSegment> al = null;    public FastCollinearPoints(Point[] points) {        if (points == null)            throw new NullPointerException();                Point[] points1 = new Point[points.length];        System.arraycopy(points, 0, points1, 0, points.length);        al = new ArrayList<LineSegment>();        Quick3way.sort(points1);    // 保证所有点都在前一个点的右上方。        findDuplicate(points1);    // 去除重复点 , 因为算法本身复杂度较高,加 一个线性复杂度的方法。。无所谓了。。        for (int i = 0; i < points1.length - 3; i++) {    // 保留最后3个,加上originPoint,正好构成一个4个点的,后面的再遍历也没意义了,还会诱发NullPointerException            if (points1[i] == null)                throw new NullPointerException();                        Point[] otherPoints = new Point[points1.length - 1];    // 除了originPoint ,其它点都在这里            Point originPoint = points1[i];    // 从这点画出连接其它点的射线            for (int j = 0, k = 0; k < otherPoints.length; j++, k++) {    // initialize otherPoints[]                if (points1[j] == null)                    throw new NullPointerException();                if (j < i)                    otherPoints[k] = points1[j];                else if (j == i)                    k--;                else                    otherPoints[k] = points1[j];                            }            Arrays.sort(otherPoints, originPoint.slopeOrder());    // 按照斜率排序            int tempNum = 1;    // 相同斜率的线条数,一开始肯定有一条,凑够3条就有4个点了,源点 + 3。            double tempSlope = originPoint.slopeTo(otherPoints[0]);            for (int j = 1; j < otherPoints.length; j++) {                if (Double.compare(tempSlope, originPoint.slopeTo(otherPoints[j])) != 0) {                    if (tempNum >= 3) {                        Point[] temp = new Point[tempNum + 1];    // 把能组成直线的点放到temp里面                        temp[0] = originPoint;    // put originPoint into temp[0]                        for (int k = 1; k <= tempNum; k++) {                            temp[k] = otherPoints[j - k];                        }                        int indexOfMin = findMin(temp);    // 找出最小的点,也就是源点                        if (temp[indexOfMin] == originPoint) {    // 如果最小点不是源点,就说明这个条线之前已经统计过了,直接跳过。                            Point head = temp[indexOfMin], tail = temp[indexOfMin];    // 找到头尾                            for (int l = 1; l < temp.length; l++) {                                if (temp[l].compareTo(head) < 0)                                    head = temp[l];                                if (temp[l].compareTo(tail) > 0)                                    tail = temp[l];                            }                            al.add(new LineSegment(head, tail));                            num++;                        }                    }                    tempNum = 1;    // 还原初始条件,并重设斜率                    tempSlope = originPoint.slopeTo(otherPoints[j]);                }                else {                    tempNum++;                }            }            if (tempNum >= 3) {    // 防止末尾的直线没计入,可能最后斜率没变化就默默结束了                Point[] temp = new Point[tempNum + 1];    // 把能组成直线的点放到temp里面                temp[0] = originPoint;    // put originPoint into temp[0]                for (int k = 0; k < tempNum; k++) {                    temp[k + 1] = otherPoints[otherPoints.length -1 - k];                }                int indexOfMin = findMin(temp);                if (temp[indexOfMin] == originPoint) {                    Point head = temp[indexOfMin], tail = temp[indexOfMin];    // 找到头尾                    for (int l = 1; l < temp.length; l++) {                        if (temp[l].compareTo(head) < 0)                            head = temp[l];                        if (temp[l].compareTo(tail) > 0)                            tail = temp[l];                    }                    al.add(new LineSegment(head, tail));                    num++;                }            }        }     }        /**     * 寻找最小点     */    private int findMin(Point[] temp) {            int index = 0;        Point a = temp[0];        for (int i = 1; i < temp.length; i++) {            if (a.compareTo(temp[i]) > 0) {                a = temp[i];                index = i;            }        }        return index;    }    /**     * 排除重复     */        private void findDuplicate(Point[] points1) {        for (int i = 0; i < points1.length - 1; i++) {            if (points1[i].compareTo(points1[i + 1]) == 0)                throw new IllegalArgumentException();        }    }        public int numberOfSegments() {        // the number of line segments        return num;    }    public LineSegment[] segments() {        return al.toArray(new LineSegment[num]);    }        public static void main(String[] args) {        // read the n points from a file        int n = StdIn.readInt();        Point[] points = new Point[n];        for (int i = 0; i < n; i++) {            int x = StdIn.readInt();            int y = StdIn.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        FastCollinearPoints collinear = new FastCollinearPoints(points);        StdOut.println(collinear.segments().length);        for (LineSegment segment : collinear.segments()) {            StdOut.println(segment);            segment.draw();        }        StdDraw.show();    }}


还是把point也放进来,方便看。。

import java.util.Comparator;import edu.princeton.cs.algs4.StdDraw;public class Point implements Comparable<Point> {    private final int x;     // x-coordinate of this point    private final int y;     // y-coordinate of this point    public Point(int x, int y) {        if (x < 0 || x > 32767 || y < 0 || y > 32767)            throw new IllegalArgumentException();        this.x = x;        this.y = y;    }    /**     * Draws this point to standard draw.     */    public void draw() {        StdDraw.point(x, y);    }    /**     * Draws the line segment between this point and the specified point to standard draw.     *     * @param that     *            the other point     */    public void drawTo(Point that) {        StdDraw.line(this.x, this.y, that.x, that.y);    }    /**     * Returns the slope between this point and the specified point. Formally, if the two points are (x0, y0) and (x1, y1), then the slope is (y1 - y0) / (x1 -     * x0). For completeness, the slope is defined to be +0.0 if the line segment connecting the two points is horizontal; Double.POSITIVE_INFINITY if the line     * segment is vertical; and Double.NEGATIVE_INFINITY if (x0, y0) and (x1, y1) are equal.     *     * @param that     *            the other point     * @return the slope between this point and the specified point     */    public double slopeTo(Point that) {        if (this.compareTo(that) == 0)            return Double.NEGATIVE_INFINITY;    // Same pint        else if (this.x == that.x)            return Double.POSITIVE_INFINITY;    // Vertical        else if (this.y == that.y)            return +0.0;                        // Horizontal        else            return (that.y - this.y) * 1.0 / (that.x - this.x);    }    /**     * Compares two points by y-coordinate, breaking ties by x-coordinate. Formally, the invoking point (x0, y0) is less than the argument point (x1, y1) if and     * only if either y0 < y1 or if y0 = y1 and x0 < x1.     *     * @param that     *            the other point     * @return the value <tt>0</tt> if this point is equal to the argument point (x0 = x1 and y0 = y1); a negative integer if this point is less than the     *         argument point; and a positive integer if this point is greater than the argument point     */    public int compareTo(Point that) {        if (this.y > that.y)            return 1;        else if (this.y < that.y)            return -1;        else if (this.y == that.y && this.x > that.x)            return 1;        else if (this.y == that.y && this.x < that.x)            return -1;        else            return 0;    }    /**     * Compares two points by the slope they make with this point. The slope is defined as in the slopeTo() method.     *     * @return the Comparator that defines this ordering on points     */    public Comparator<Point> slopeOrder() {        return new SlopeOrder();    }    private class SlopeOrder implements Comparator<Point> {        public int compare(Point p1, Point p2) {            double slope1 = slopeTo(p1);            double slope2 = slopeTo(p2);            return Double.compare(slope1, slope2);        }    }    /**     * Returns a string representation of this point. This method is provide for debugging; your program should not rely on the format of the string     * representation.     *     * @return a string representation of this point     */    public String toString() {        return "(" + x + ", " + y + ")";    }    /**     * Unit tests the Point data type.     */    public static void main(String[] args) {        /* YOUR CODE HERE */    }}




0 0
原创粉丝点击