[英]Sorting: An alternative to HashMaps and Sets?
我正在尝试在 Coursera 中开设一门名为 Algorithms, part 1 的免费课程。在其中一项作业中,我们被要求使用 devise 和算法来查找图中的所有共线点集。 以下是更多规格的链接:
https://coursera.cs.princeton.edu/algs4/assignments/collinear/specification.php 。
在 class FastCollinearPoints 中,我们被要求实现以下算法:
将 p 视为原点。
对于每个其他点 q,确定它与 p 的斜率。
根据它们与 p 形成的斜率对点进行排序。
检查排序顺序中是否有 3 个(或更多)相邻点相对于 p 具有相等的斜率。 如果是这样,这些点连同 p 是共线的。
这是我制作的 class 的一部分:
private ArrayList<LineSegment> segments = new ArrayList<>();
private HashMap<Double, ArrayList<Point>> slopeEndPoints = new HashMap<>();
// finds all line segments containing 4 or more points
public FastCollinearPoints(Point[] points) {
if(points == null)
throw new IllegalArgumentException("Null Argument: points");
int N = points.length;
Point[] pointsCopy = Arrays.copyOf(points, points.length);
Arrays.parallelSort(pointsCopy);
checkCornerCases(pointsCopy);
for(int p = 0; p < N-3; p++) {
Point[] ptsInRange = Arrays.copyOfRange(pointsCopy, p, N);
Arrays.parallelSort(ptsInRange, ptsInRange[0].slopeOrder());
int first = 1, last = 2;
while(last < ptsInRange.length) {
double slope = ptsInRange[0].slopeTo(ptsInRange[first]);
while(last < ptsInRange.length
&& Double.compare(slope, ptsInRange[0].slopeTo(ptsInRange[last])) == 0)
last++;
if(last - first > 2)
if(isSelected(slope, ptsInRange, last-1))
segments.add(new LineSegment(ptsInRange[0], ptsInRange[last-1]));
first = last;
last++;
}
}
}
private boolean isSelected(double slope, Point[] points, int end) {
ArrayList<Point> selection = this.slopeEndPoints.get(slope);
if(selection == null) {
selection = new ArrayList<Point>();
selection.add(points[end]);
this.slopeEndPoints.put(slope, selection);
return true;
}
else if(selection.contains(points[end]))
return false;
else {
selection.add(selection.size(), points[end]);
this.slopeEndPoints.put(slope, selection);
return true;
}
当我提交答案时,我收到以下反馈:
FastCollinearPoints.java:9:17:请勿在此分配中使用“HashMap”数据类型。 Hash 表尚未在课程中介绍(并且不会达到最坏情况的性能要求)。 相反,使用排序。 [表现]
所以我想知道:“使用排序”是什么意思? 通过排序可以得到和HashMap一样的效果吗? 如何?
可能有人会在这里为您编写代码,我坚信它不会让您学习,所以让我们尝试了解算法中发生了什么。
所以有两件事(你可以在问题中清除),但让我们在这里分解一下 -
在图中查找所有共线点集
对于固定点P
,实现您刚才提到的算法。
让我们先从第 2 部分开始:您发布的 java 解决方案太过分了,您根本不需要HashMaps
。
考虑这件作品:
// declare Point P
class Point {
int x, y; //
double slope; // slope = y/x
}
double getSlope(Point a) {
return (double)(a.y - P.y) / (a.x - P.x);
}
// declare list of points as List<Point> ptList
Collections.sort(ptList, new Comparator<Point>() {
@Override
public int compare(Point a, Point b) {
return getSlope(a) < getSlope(b);
}
});
for(int i = 1; i < ptList.length(); i++) {
if(getSlope(ptList[i]) == getSlope(ptList[i - 1]) {
// this means points i, i - 1 have equal slopes
}
}
这是基于这样一个事实,即相等的数字在排序后组合在一起。 例如,一个未排序的数组[0, 2, 1, 2, 0, 3, 1, 1]
在排序[0, 0, 1, 1, 1, 2, 2, 3]
后看起来像这样元素在一起。
现在第 1 部分:我们需要找到所有这些集合。 我们将尝试将给定列表P
中的每个点,以及尚未处理的点的 rest 作为集合Q
。 使用上述过程,我们可以将点集Q
划分为共线集。
当您为所有P
完成此操作时,您就完成了。
PS - 请不要直接使用val1 == val2
比较双精度值,因为浮点精度会失败。 使用基于阈值的比较,例如absolute(val1 - val2) < 10^(-9)
更多阅读: https://howtodoinjava.com/java/basics/correctly-compare-float-double/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.