平面最近点对问题,将对X中的点按横坐标排序,对Y中的点按纵坐标排序,移出递归实现Θ( log⁡)的时间复杂度。

首先实现 Point 类,用于存储每一点的坐标数据。

class Point {
    double x, y;
    
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

实现两点间距离计算方法 distance(p1, p2), 用于计算两点间距离。

double distance(Point p1, Point p2) {
    double dx = p1.x - p2.x;
    double dy = p1.y - p2.y;
    return Math.sqrt(dx * dx + dy * dy);
}

创建一个比较器,使得集合中的点按照它们的 xy 坐标从小到大排列。Collections.sort 是 Java 中用于对集合进行排序的方法,它接受一个比较器(Comparator)作为参数,以确定如何排序集合中的元素。

 // 按照它们的x坐标进行非递减排序
Collections.sort(points, 
                 Comparator.comparingDouble(p -> p.x));

 // 按照它们的y坐标进行非递减排序
Collections.sort(points, 
                 Comparator.comparingDouble(p -> p.y));

当计算的点的数量小于等于3时,直接使用暴力算法求解最短距离。

double enumeratePair(List<Point> points, int low, int high) {
    double minDistance = Double.POSITIVE_INFINITY;
    for (int i = low; i <= high; i++) {
        for (int j = i + 1; j <= high; j++) {
            minDistance = Math.min(minDistance,
                                   distance(points.get(i),
                                            points.get(j)));
        }
    }
    return minDistance;
}

实现merge(yl, yr)方法,用于合并Yl和Yr,进行一次排序,避免在递归中调用排序算法。

List<Point> merge(List<Point> Yl, List<Point> Yr) {
    List<Point> Y = new ArrayList<>(Yl.size() + Yr.size());
    Y.addAll(Yl);
    Y.addAll(Yr);
    // 按照y坐标非递减排序
    Collections.sort(Y, 
                     Comparator.comparingDouble(p -> p.y));
    return Y;
}

实现compute()方法,用于计算T(临时列表)中的点的最小距离。

double compute(List<Point> Y, double delta){
    // 中间点的x坐标
    double x0 = Y.get((int) (Y.size() / 2)).x; 
    // 临时列表
    List<Point> T = new ArrayList<>(); 
    int k = 0;

    for (int i = 0; i < Y.size(); i++) {
        Point point = Y.get(i);
        if (Math.abs(point.x - x0) <= delta) {
            k++;
            T.add(point);
        }
    }

    // 计算T的大小
    int tSize = T.size();
    double deltaPrime = 2 * delta;

    // 对T中的点进行最小距离计算
    for (int i = 0; i < tSize - 1; i++) {
        for (int j = i + 1; j < Math.min(i + 8, tSize); j++) {
            double dist = distance(T.get(i), T.get(j));
            if (dist < delta) {
                delta = dist;
            }
        }
    }

    // 返回最小距离
    return delta;
}

实现cp()方法,分治计算最短距离。

​ 1 出口为当前子问题的规模小于3,可以直接求解最短距离。

if (high - low + 1 <= 3) {
    return enumeratePair(points, low, high);
}

​ 2 获取中点的索引,并使用cp(low, mid)计算(δ1, Yl)cp(mid + 1, high)计算(δr, Yr),获得δ = min{δl, δr}

int mid = (low + high) / 2;
Point midPoint = points.get(mid);

List<Point> Yl = new ArrayList<>();
List<Point> Yr = new ArrayList<>();
// 根据x坐标划分左右
for (Point y : ySorted) {
    if (y.x <= points.get(mid).x) {
        Yl.add(y);
    } else {
        Yr.add(y);
    }
}

double deltaLeft = cp(points, yl, low, mid);
double deltaRight = cp(points, yr, mid + 1, high);

double delta = Math.min(deltaLeft, deltaRight);

​ 3 归并YlYr,计算临时列表中的最短距离,与两侧的最短距离进行比较,返回最小值。

List<Point> Y = merge(Yl, Yr);
return compute(Y, delta);

​ 进行计算前,先对点集 points进行预处理,按照x坐标进行非递减排序。

int n = points.size();
if (n < 2) {
    // 点数量无法构成一个点对,返回无穷大
    return Double.POSITIVE_INFINITY; 
}
// 按照它们的x坐标进行非递减排序
Collections.sort(points, 
         Comparator.comparingDouble(p -> p.x));
// 复制排序后的点集到Y列表
List<Point> ySorted = new ArrayList<>(points);
// 对Y列表按照y坐标进行非递减排序
Collections.sort(ySorted, 
                 Comparator.comparingDouble(p -> p.y));

​ 3.9 完整代码:

import java.util.*;

class Point {
    double x, y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

public class ClosestPair {
    // 计算两点之间的距离
    public static double distance(Point p1, Point p2) {
        double dx = p1.x - p2.x;
        double dy = p1.y - p2.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

    public static double enumeratePair(List<Point> points, int low, int high) {
        double minDistance = Double.POSITIVE_INFINITY;
        for (int i = low; i <= high; i++) {
            for (int j = i + 1; j <= high; j++) {
                minDistance = Math.min(minDistance, distance(points.get(i), points.get(j)));
            }
        }
        return minDistance;
    }

    // 合并Yl和Yr
    private static List<Point> merge(List<Point> Yl, List<Point> Yr) {
        List<Point> Y = new ArrayList<>(Yl.size() + Yr.size());
        Y.addAll(Yl);
        Y.addAll(Yr);
        // 按照y坐标非递减排序
        Collections.sort(Y, Comparator.comparingDouble(p -> p.y));
        return Y;
    }

    private static double compute(List<Point> Y, double delta){
        // 中间点的x坐标
        double x0 = Y.get((int) (Y.size() / 2) - 1).x; 
        // 临时列表
        List<Point> T = new ArrayList<>(); 
        int k = 0;
    
        for (int i = 0; i < Y.size(); i++) {
            Point point = Y.get(i);
            if (Math.abs(point.x - x0) <= delta) {
                k++;
                T.add(point);
            }
        }
    
        // 计算T的大小
        int tSize = T.size();
        double deltaPrime = 2 * delta;
        // 对T中的点进行最小距离计算
        for (int i = 0; i < tSize - 1; i++) {
            for (int j = i + 1; j < Math.min(i + 8, tSize); j++) {
                double dist = distance(T.get(i), T.get(j));
                if (dist < delta) {
                    delta = dist;
                }
            }
        }
    
        // 返回最小距离
        return delta;
    }

    // 递归计算最近点对的函数
    private static double cp(List<Point> points, List<Point> ySorted, int low, int high) {
        if (high - low + 1 <= 3) {
            // 如果点的数量小于等于3,使用暴力方法计算最近点对距离
            return enumeratePair(points, low, high);
        }

        int mid = (low + high) / 2;
        List<Point> Yl = new ArrayList<>();
        List<Point> Yr = new ArrayList<>();

        for (Point y : ySorted) {
            if (y.x <= points.get(mid).x) {
                Yl.add(y);
            } else {
                Yr.add(y);
            }
        }

        double deltaLeft = cp(points, Yl, low, mid);
        double deltaRight = cp(points, Yr, mid + 1, high);

        double delta = Math.min(deltaLeft, deltaRight);

        List<Point> Y = merge(Yl, Yr);
        return compute(Y, delta);
    }

    public static double closestPair(List<Point> points) {
        if (points.size() < 2) {
            // 如果点的数量小于2,无法计算最近点对距离
            return Double.POSITIVE_INFINITY;
        }

        // 按照它们的x坐标进行非递减排序
        Collections.sort(points, 
             			Comparator.comparingDouble(p -> p.x));
        // 复制排序后的点集到Y列表
        List<Point> ySorted = new ArrayList<>(points);
        // 对Y列表按照y坐标进行非递减排序
        Collections.sort(ySorted, 
                     	Comparator.comparingDouble(p -> p.y));

        return cp(points, ySorted, 0, points.size() - 1);
    }
    public static void main(String[] args) {
        // 创建示例点集
        List<Point> points = new ArrayList<>();
        points.add(new Point(0, 0));
        points.add(new Point(1, 2));
        points.add(new Point(2, 4));
        points.add(new Point(3, 1));
        points.add(new Point(6, 7));
        points.add(new Point(7, 0));

        // 计算最近点对距离
        double minDistance = closestPair(points);
        System.out.println("最近点对距离为:" + minDistance);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值