简体   繁体   English

Java快速找到k个最接近给定2D点的点

[英]Java find k closest points to a given 2D point, quickly

I function that takes a set of points, checks their distance against a given point and returns an ordered set with the closest points first. 我的功能是获取一组点,检查它们与给定点的距离,并首先返回最接近点的有序集合。 In case 2 points have the same distance from the given point, both will be kept, no problem. 如果2个点到给定点的距离相同,则两个点都将保留,没有问题。

I use that function to pick the k closest points to any user-given point with 2D coordinates. 我使用该功能从2D坐标中选择k个最接近用户给定点的点。 It's just a matter of picking the first k points from the ordered set. 只需从有序集合中选择前k个点即可。

Right now it's something like this, and I guess the distance calculation is called again and again for every point that's added (not good) 现在是这样的,我想距离计算每次添加的点都会被反复调用(不好)

import java.awt.geom.Point2D;
import java.util.Comparator;

/**
 * This comparator sorts two points by destination distance.
 */
public class NearestComparator implements Comparator<Point2D> {

    /** The point to be reached. */
    private Point2D destination;

    /**
     * Instantiates a new comparator that sorts points by destination distance, descendant.
     * 
     * @param destination the point to reach
     */
    public NearestComparator(Point2D destination) {
        this.destination = destination;
    }

    /**
     * Sort two points by destination distance, descendant.
     * 
     * @param p1 the first point
     * @param p2 the second point
     */
    @Override
    public int compare(Point2D p1, Point2D p2) {
        double p1_distance = p1.distance(destination);
        double p2_distance = p2.distance(destination);
        return (p1_distance < p2_distance) ? -1 : ((p1_distance > p2_distance) ? 1 : 0);
    }
}

The sorting code right now is like this 现在的排序代码是这样的

private List<Point2D> getSendOrder(Point2D destination) {
    LinkedList<Point2D> sendOrderList = new LinkedList<Point2D>();
    sendOrderList.add(myPosition);

    Iterator<Point2D> keyIter = neighborLinks.keySet().iterator();
    while (keyIter.hasNext()) {
        sendOrderList.add(keyIter.next());
    }

    // sort list by distance from destination
    Collections.sort(sendOrderList, new NearestComparator(destination));
    return sendOrderList;
}

Is there a data structure in the standard library that allows me to add an element with a fixed "priority" that is unrelated to its own class? 标准库中是否有数据结构,可让我添加一个固定的“优先级”与它自己的类无关的元素? I mean, something like (priority 1, Object ref x) , (priority 2, Object ref y) , (priority 1, Object ref z) etc. 我的意思是,类似(priority 1, Object ref x)(priority 2, Object ref y)(priority 1, Object ref z)等。

I need this to be as fast as possible, and to generate as little garbage as possible. 我需要此速度尽可能快,并产生尽可能少的垃圾。 It's for a routing algorithm in a graph. 用于图中的路由算法。 There is no need for fast access to the middle of the ordered set, just the top (lowest distance, highest priority). 无需快速访问排序集中的中间,只需访问顶部(最小距离,最高优先级)即可。 It's important however to be able to remove the top priority element in an efficient way. 但是,重要的是要能够有效地删除最优先的元素。

As you can see, as long as I get a list ordered in the right way (first element has higher priority, etc.), I have no need to preserve the priority information in the returned result. 如您所见,只要我以正确的方式排序列表(第一个元素具有更高的优先级,等等),我就无需在返回的结果中保留优先级信息。

I've had the idea to wrap the distance using Map.Entry, then this also allows deep copy, if you want it. 我曾想过使用Map.Entry包装距离,然后如果需要的话还可以进行深度复制。

Here's a complete example 这是一个完整的例子

package sandbox;

import java.awt.geom.Point2D;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

public class Node {

    private Point2D myPosition;
    private Map<Point2D, Node> neighborLinks;

    public class NearestComparator implements Comparator<Entry> {

        @Override
        public int compare(Entry e1, Entry e2) {
            return Double.compare((Double) e1.getValue(), (Double) e2.getValue());
        }
    }

    public List<Point2D> getSendOrder(Point2D destination) {
        LinkedList<Entry> sendOrderList = new LinkedList<>();
        Entry<Point2D, Double> pointWithDist;

        // calculate distance from destination and wrap it using an Entry
        pointWithDist = new SimpleEntry<>(myPosition, myPosition.distance(destination));
        sendOrderList.add(pointWithDist);
        for (Point2D otherPoint : neighborLinks.keySet()) {
            pointWithDist = new SimpleEntry<>(otherPoint, otherPoint.distance(destination));
            sendOrderList.add(pointWithDist);
        }

        // sort list by distance from destination
        Collections.sort(sendOrderList, new NearestComparator());

        // print all the list (debug)
        System.out.println(Arrays.toString(sendOrderList.toArray()));

        // unwrap and deep copy
        LinkedList<Point2D> copiedList = new LinkedList<>();
        Point2D pointToCopy, copiedPoint;
        for (Entry entry : sendOrderList) {
            pointToCopy = (Point2D) entry.getKey();
            copiedPoint = new Point2D.Double(pointToCopy.getX(), pointToCopy.getY());
            copiedList.add(copiedPoint);
        }

        return copiedList;
    }

    public Node(Point2D myPosition, Map<Point2D, Node> neighborLinks) {
        this.myPosition = myPosition;
        this.neighborLinks = neighborLinks;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Map<Point2D, Node> neighborLinks = new HashMap<>();
        Random rand = new Random();
        double x, y, max = 5;
        for (int i = 0; i < 10; ++i) {
            x = rand.nextDouble() * max;
            y = rand.nextDouble() * max;
            neighborLinks.put(new Point2D.Double(x, y), null);
        }

        Point2D nodePos = new Point2D.Double();
        Node myNode = new Node(nodePos, neighborLinks);

        Point2D destination = new Point2D.Double();
        myNode.getSendOrder(destination);
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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