繁体   English   中英

排序:HashMaps 和 Sets 的替代方案?

[英]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一样的效果吗? 如何?

可能有人会在这里为您编写代码,我坚信它不会让您学习,所以让我们尝试了解算法中发生了什么。

所以有两件事(你可以在问题中清除),但让我们在这里分解一下 -

  1. 在图中查找所有共线点集

  2. 对于固定点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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM