-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathFastCollinearPoints.java
128 lines (109 loc) · 3.72 KB
/
FastCollinearPoints.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;
import java.util.*;
public class FastCollinearPoints {
private ArrayList<LineSegment> lineSegments = new ArrayList<>();
private HashMap<Double, List<Point>> slopeToEndPoints = new HashMap<>();
/**
* finds all line segments containing 4 or more points
*/
public FastCollinearPoints(Point[] points) {
validateNotNull(points);
for (Point p : points) {
validateNotNull(p);
}
Point[] sortedPoints = points.clone();
Arrays.sort(sortedPoints);
checkDup(sortedPoints);
for (int i = 0; i < sortedPoints.length; i++) {
Arrays.sort(sortedPoints, i, sortedPoints.length);
Point origin = sortedPoints[i];
Arrays.sort(sortedPoints, i + 1, sortedPoints.length, origin.slopeOrder());
int count = 0;
double prevSlope = Double.NaN;
Point prevPoint = origin;
for (int j = i + 1; j < sortedPoints.length; j++) {
Point point = sortedPoints[j];
double slope = origin.slopeTo(point);
if (Double.compare(slope, prevSlope) == 0) {
count += 1;
} else {
if (count >= 3) {
addIfNotExisted(origin, prevPoint, prevSlope);
}
prevSlope = slope;
count = 1;
}
prevPoint = point;
}
if (count >= 3) {
addIfNotExisted(origin, prevPoint, prevSlope);
}
}
}
private void addIfNotExisted(Point start, Point end, double slope) {
List<Point> existedPoints = slopeToEndPoints.get(slope);
if (existedPoints == null) {
existedPoints = new ArrayList<>();
existedPoints.add(end);
slopeToEndPoints.put(slope, existedPoints);
lineSegments.add(new LineSegment(start, end));
} else {
if (!existedPoints.contains(end)) {
existedPoints.add(end);
lineSegments.add(new LineSegment(start, end));
}
}
}
private void checkDup(Point[] sortedPoints) {
for (int i = 0; i < sortedPoints.length - 1; i++) {
if (sortedPoints[i].compareTo(sortedPoints[i + 1]) == 0) {
throw new IllegalArgumentException();
}
}
}
private void validateNotNull(Object o) {
if (o == null) {
throw new IllegalArgumentException();
}
}
/**
* the number of line segments
*/
public int numberOfSegments() {
return lineSegments.size();
}
/**
* the line segments
*/
public LineSegment[] segments() {
return lineSegments.toArray(new LineSegment[]{});
}
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
FastCollinearPoints collinear = new FastCollinearPoints(points);
for (LineSegment segment : collinear.segments()) {
StdOut.println(segment);
segment.draw();
}
StdDraw.show();
}
}