(二)最近点对问题

113 阅读1分钟
public class Point {
    private double x;
    private double y;
 }

public class ClosestPoint {
    public static void main(String[] args) {
        List<Point> points = new ArrayList<>();
        getData(points, 8);
        System.out.println(points);
        Point p1 = new Point();
        Point p2 = new Point();
        System.out.println(ClosestDistance(points, p1, p2));
        System.out.println(p1 + "" + p2);

    }

    public static double ClosestDistance(List<Point> points, Point P1, Point P2) {
        List<Point> X = new ArrayList<>();
        List<Point> Y = new ArrayList<>();
        for (Point point : points) {
            X.add(point);
            Y.add(point);
        }
        Collections.sort(X, (p1, p2) -> p1.getX() - p2.getX() < 0 ? -1 : 1);
        Collections.sort(Y, (p1, p2) -> p1.getY() - p2.getY() < 0 ? -1 : 1);

        return getClosestPointPair(X, Y, P1, P2);
    }

    /**
     * @param X 根据x排序好的点集
     * @param Y 根据y排序好的点集
     * @return 最小点对的距离
     */
    public static double getClosestPointPair(List<Point> X, List<Point> Y, Point p1, Point p2) {
        double minLeft, minRight, minDistance = 0;
        Point pl1 = new Point();
        Point pl2 = new Point();
        Point pr1 = new Point();
        Point pr2 = new Point();
        if (X.size() <= 3) {
            double res = ClosestLowThree(X, pl1, pl2);
            p1.setX(pl1.getX());
            p1.setY(pl1.getY());
            p2.setX(pl2.getX());
            p2.setY(pl2.getY());
            return res;
        }


        List<Point> pl = new ArrayList<>();
        List<Point> pr = new ArrayList<>();
        int mid = X.size() / 2;
        for (int i = 0; i < mid; i++)
            pl.add(X.get(i));
        for (int j = mid; j < X.size(); j++)
            pr.add(X.get(j));

        List<List<Point>> list = YTwo(pl, pr, Y);
        List<Point> YL = list.get(0);
        List<Point> YR = list.get(1);
        minLeft = getClosestPointPair(pl, YL, pl1, pl2);
        minRight = getClosestPointPair(pr, YR, pr1, pr2);
        if (minLeft < minRight) {
            p1.setX(pl1.getX());
            p1.setY(pl1.getY());
            p2.setX(pl2.getX());
            p2.setY(pl2.getY());
        } else {
            p1.setX(pr1.getX());
            p1.setY(pr1.getY());
            p2.setX(pr2.getX());
            p2.setY(pr2.getY());
        }

        minDistance = Math.min(minLeft, minRight);
        List<Point> Y1 = new ArrayList<>();
        for (int i = 0; i < Y.size(); i++) {
            if (Math.abs(Y.get(i).getX() - mid) < minDistance)
                Y1.add(Y.get(i));
        }
        for (int i = 0; i < Y1.size(); i++)
            for (int j = i + 1; j <= i + 7 && j < Y1.size(); j++) {
                double distance = distance(Y1.get(i), Y1.get(j));
                if (distance < minDistance) {
                    minDistance = distance;
                    p1.setX(Y1.get(i).getX());
                    p1.setY(Y1.get(i).getY());
                    p2.setX(Y1.get(j).getX());
                    p2.setY(Y1.get(j).getY());
                }

            }
        return minDistance;
    }

    /**
     * @param Pl 根据X划分的左半部分
     * @param Pr 分局X划分的右半部分
     * @param Y  根据Y排序的集合
     * @return 返回根据Y划分的左右两部分
     */
    public static List<List<Point>> YTwo(List<Point> Pl, List<Point> Pr, List<Point> Y) {
        List<Point> YL = new ArrayList<>();
        List<Point> YR = new ArrayList<>();
        for (int i = 0; i < Y.size(); i++) {
            if (Pl.contains(Y.get(i)))
                YL.add(Y.get(i));
            else
                YR.add(Y.get(i));
        }
        List<List<Point>> res = new ArrayList<>();
        res.add(YL);
        res.add(YR);
        return res;
    }

    /**
     * @param p1 点1
     * @param p2 点2
     * @return 两点距离
     */
    public static double distance(Point p1, Point p2) {
        return Math.sqrt((p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) + (p1.getY() - p2.getY()) * (p1.getY() - p2.getY()));
    }

    /**
     * @param list
     * @return 低于3个的点暴力最小值
     */
    public static double ClosestLowThree(List<Point> list, Point p1, Point p2) {
        if (list.size() == 0)
            return 0.0;
        double minAns = Double.MAX_VALUE;
        for (int i = 0; i < list.size(); i++)
            for (int j = i + 1; j < list.size(); j++) {
                double distance = distance(list.get(i), list.get(j));
                if (distance < minAns) {
                    minAns = distance;
                    p1.setX(list.get(i).getX());
                    p1.setY(list.get(i).getY());
                    p2.setX(list.get(j).getX());
                    p2.setY(list.get(j).getY());
                }

            }
        return minAns;
    }



    //从文件中读取数据
    public static void getData(List<Point> points, int l) {
        //将稀疏矩阵从文件中读取出来
        BufferedReader bufferedReader = null;
        //为保存的数组分配空间
        try {

            InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(new File("F:\java\leetcode\src\algorithm\project2\data.txt")));
            bufferedReader = new BufferedReader(inputStreamReader);
            String line = null;
            int i = 0;
            //按行读取
            while ((line = bufferedReader.readLine()) != null) {
                if (i == l)
                    break;
                if (null != line) {
                    //将按行读取的字符串按空格分割,得到一个string数组
                    String[] strings = line.split("\s+");
                    //依次转换为int类型存入到分配好空间的数组
                    Point p = new Point();
                    for (int k = 0; k < 2; k++) {
                        if (k == 0)
                            p.setX(Double.valueOf(strings[k]));
                        else
                            p.setY(Double.valueOf(strings[k]));
                    }
                    points.add(p);
                    //行数加1
                    i++;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}