分治法求最近点对( java )

分治法求最近点对问题

这个问题熬了我一个晚上改错,都是空指针错误,从网上看了好多资料都没什么用,但就是那一瞬间看到了代码的某一行发现了错误,在数据与数组中某个值比较时,数组范围弄错了,导致比较过程中会指向数组外的地方(还是空指针问题)。现写下分析过程,以便后续查验
问题描述
在这里插入图片描述补充要求:随机生成横纵坐标值均在1-10的30个点(浮点数),递归求出距离最近的一对点的坐标及其该两点距离值并以显示。
时间复杂度
如果是用蛮力法,那么时间复杂度毫无疑问是O(n^2),并不是最优解。现采用分治法递归函数,使之时间复杂度为O(nlogn)。
基本思想
30个点为0到29,数集为S。
基本思想:将S分成左右不相交的两个子集,求每个子集的最近点对,以及分别位于两个子集中的
所有点对的最近点对(由左边一个点,右边一个点构成),最后通过比较得到S中的最近点对。
做法
(1)当n≤2时直接求解。n为1时则返回一个double型的最大值,n为2时则记录两点并返回两点间距离。n>3时按如下步骤。
(2)分解:根据x坐标,对S中的点升序排序,以经过第n/2个点做中垂线,分为左右两侧,将S均分成两个子集:S[1…m] 和[m+1…n] ,其中 (int) m=n/2 。这样,一部分在中垂线的左边或在中垂线上,另一部分在中垂线右边或在中垂线上。
(3)递归:用同样的分治算法分别求中垂线两边的最近点对的距离min1和min2。
(4)组合:比较min1和min2,取较小值赋给mint,求中垂线左边一个点和右边一个点的最近距离看其是否小于mint,若小于则改变点对,更新mint。
难点:求中垂线左边一个点和右边一个点的最近距离
如果还是左边和右边一个一个算的话,又回到了O(n^2)。事实上不用遍历每一个点,有些点没有必要去算。先给出具体方法:我们现已比较出左侧和右侧两方的最短距离mint,那么以中垂线为界两边扩展mint的距离,可能符合要求的点均在这个区域内。这些点可以比较其与中垂线的距离来筛选,x的差距绝对值小于mint的进入新的数组K[n]。如图:
在这里插入图片描述
那么K中数据怎么比较呢,现介绍一个方式。
取一个mint×2*mint方框,若其中不存在小于mint的点对,那么这个方框中最多存在六个点。
在这里插入图片描述
所以我们往K里放数据时应是按y的值从小到大排好的,这样我们遍历K的时候只需往后多找六个点就行
了。这样使得此过程时间复杂度为O(n)。但是需提前将30个点分别按x和y排好顺序,存到两个数组中,以便后续使用。
上代码(如有人查看,请不要直接搬抄代码,无意义)

import java.util.Arrays;
import java.util.Comparator;
public class MinDistance {
   static Points point = new Points();
  public static void main(String[] args) {
    node[] a = new node[30];
    createPoint(a);
    node[] b = a.clone();
    Arrays.sort( a , new cmp1() );  //按x排序
    Arrays.sort( b , new cmp2() );  //按y排序
    double dis = minDis(0,29,a,b,point);    
    System.out.println("最近点对:");
    System.out.println("( "+point.x1+" , "+point.y1+" ),"+"( "+point.x2+" , "+point.y2+" )");
    System.out.println("最近距离:"+dis);
}
   public static void createPoint(node[] a) {     //创建随机点
    for(int i=0;i<30;i++)
    {
     a[i] = new node();
     a[i].x = 10*Math.random();
     a[i].y = 10*Math.random();
     for(int j=0;j<i;j++) {
      if( a[j].x==a[i].x && a[j].y==a[i].y ) {
       i--;
       break;
      }
     }
    }
   }
   public static double distance(int i,int j,node[] a) {  //计算距离
    double n = Math.pow(a[i].y-a[j].y, 2);   
    double m = Math.pow(a[i].x-a[j].x, 2);
    double w = Math.sqrt(m+n);
    return w;
   }
   public static double minDis(int low,int high,node[] a,node[] b,Points p) {
    if(high-low==0)
     return Double.MAX_VALUE;
    else if(high-low==1) {
     p.x1 = a[low].x;
     p.x2 = a[high].x;
     p.y1 = a[low].y;
     p.y2 = a[high].y;
     return distance(low,high,a);
    }
    else {
     int m = (low+high)/2;
     Points c = new Points();
  Points d = new Points();
     double min1 = minDis(low,m,a,b,c);         
     double min2 = minDis(m+1,high,a,b,d); 
     double mint;
     if(min1 < min2){
   p.x1 = c.x1;
   p.x2 = c.x2;
   p.y1 = c.y1;
   p.y2 = c.y2;
   mint = min1;
  }else {
   p.x1 = d.x1;
   p.x2 = d.x2;
   p.y1 = d.y1;
   p.y2 = d.y2;
   mint = min2;
  }
     double x = a[m].x;
     int k = 0;
     node[] K = new node[30];
     for(int i=0;i<30;i++) {
      if(mint>=(Math.abs(b[i].x-x))) {
       K[k] = new node();
       K[k].x = b[i].x;
       K[k].y = b[i].y;
       k++;
      }
     }
     for(int i=0;i<(k-1);i++) {
      int temp = (i+7)<k?(i+7):k;
      for(int j=i+1;j<temp;j++) {      //记住此地方,空指针,为了它真是用了好长时间,长记性
       if(distance(i,j,K)<mint) {      
        mint = distance(i,j,K);
        p.x1 = K[i].x;
        p.x2 = K[j].x;
        p.y1 = K[i].y;
        p.y2 = K[j].y;
       }
      }
     }
     return mint;
    }
   }
}
class Points{       // 存储最近点对
 public double x1;
 public double y1;
 public double x2;
 public double y2;
}
class node{        //存储30个点
 public double x=0;
 public double y=0;
}
class cmp1 implements Comparator<node>{
 public int compare(node a,node b){
  if( a.x < b.x)
   return -1;
  else if(a.x >b.x)
   return 1;
  else return 0;
 }
}
class cmp2 implements Comparator<node>{
 public int compare(node a,node b){
  if( a.y < b.y)
   return -1;
  else if(a.y >b.y)
   return 1;
  else return 0;
 }
 }

个人总结,如有帮助,感谢点赞,如有问题,下方评论

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一维最接近对的分治法Java实现: ```java import java.util.*; class Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } public class ClosestPair { public static double findClosestPair(Point[] points) { Arrays.sort(points, (p1, p2) -> p1.x - p2.x); return findClosestPair(points, 0, points.length - 1); } private static double findClosestPair(Point[] points, int left, int right) { if (left >= right) { return Double.POSITIVE_INFINITY; } int mid = left + (right - left) / 2; double d1 = findClosestPair(points, left, mid); double d2 = findClosestPair(points, mid + 1, right); double d = Math.min(d1, d2); List<Point> strip = new ArrayList<>(); for (int i = left; i <= right; i++) { if (Math.abs(points[i].x - points[mid].x) < d) { strip.add(points[i]); } } Collections.sort(strip, (p1, p2) -> p1.y - p2.y); for (int i = 0; i < strip.size() - 1; i++) { for (int j = i + 1; j < strip.size() && strip.get(j).y - strip.get(i).y < d; j++) { double dist = distance(strip.get(i), strip.get(j)); if (dist < d) { d = dist; } } } return d; } private static double distance(Point p1, Point p2) { return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); } public static void main(String[] args) { Point[] points = {new Point(1, 3), new Point(2, 5), new Point(4, 6), new Point(7, 9), new Point(8, 2)}; System.out.println(findClosestPair(points)); // expected output: 1.4142135623730951 } } ``` 在此实现中,我们首先按照的x坐标进行排序。然后我们使用递归的方式将对分成两半,分别求出左边和右边的最接近对距离d1和d2。接下来,我们选取中间位置的mid,并找出所有x坐标与mid的x坐标相差小于d的。我们将这些按照y坐标进行排序,然后在其中查找距离最近对。如果找到更小的距离,则更新d。最后,我们返回d作为结果。 时间复杂度:O(nlogn) 空间复杂度:O(n)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-月光光-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值