【问题描述】
设p1=(x1,y1), p2=(x2,y2), … , pn=(xn,yn) 是平面上n个点构成的集合S,设计和实现找出集合S中距离最近点对的算法。
每一个格子最多只能存在一个点,三行最多存在12个顶点,因此对于上图中的第(i=27)个顶点来说,最多只需要比较第27个顶点与之后的11个顶点,对于i之后或之前的11个顶点之外的顶点j,即|i-j|>=12,i与j之间的距离一定大于d,因为i和j已经相隔了至少两行。两个顶点若相隔大于等于两行或两列,则他们之间的距离一定大于等于d
1 package org.xiu68.exp.exp3; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Random; 6 7 public class Exp3_2 { 8 9 //设p1=(x1,y1), p2=(x2,y2), … , pn=(xn,yn) 10 //是平面上n个点构成的集合S,设计和实现找出集合S中距离最近点对的算法。 11 public static void main(String[] args) { 12 // TODO Auto-generated method stub 13 for(int i=0;i<20;i++){ 14 System.out.println("***************************"); 15 List<Point> pointList=new ArrayList<>(); 16 for(int j=0;j<50;j++){ 17 Point p=new Point(new Random().nextInt(100),new Random().nextInt(100)); 18 pointList.add(p); 19 } 20 System.out.println(bruteforce(pointList)); //蛮力法 21 System.out.println(closestPair(pointList)); //分治法 22 23 System.out.println("****************************"); 24 } 25 } 26 27 28 29 //寻找最近点对 30 public static double closestPair(List<Point> pointList){ 31 //对pointList中的点按横坐标和纵坐标进行升序排序 32 33 List<Point> sortedListX=new ArrayList<>(); 34 List<Point> sortedListY=new ArrayList<>(); 35 36 //按横坐标对数组进行升序排序 37 pointList.sort((Point a,Point b)->{ 38 if(a.getX()<b.getX()) 39 return -1; 40 else 41 return 1; 42 }); 43 sortedListX.addAll(pointList); 44 45 //按纵坐标对数组进行升序排序 46 pointList.sort((Point a,Point b)->{ 47 if(a.getY()<b.getY()) 48 return -1; 49 else 50 return 1; 51 }); 52 sortedListY.addAll(pointList); 53 54 /* for(int i=0;i<pointList.size();i++) 55 System.out.println(sortedListX.get(i)); 56 System.out.println("*********************"); 57 for(int i=0;i<pointList.size();i++) 58 System.out.println(sortedListY.get(i)); 59 60 System.out.println("*********************"); 61 System.out.println(divide(sortedListX,sortedListY));*/ 62 63 return divide(sortedListX,sortedListY); 64 65 } 66 67 /* 68 * 原问题的分解 69 * sortedListX:横坐标升序排序的数组 70 * sortedListY:纵坐标升序排序的数组 71 */ 72 public static double divide(List<Point> sortedListX,List<Point> sortedListY){ 73 if(sortedListX.size()==1) //如果只有一个元素 74 return Double.MAX_VALUE; 75 else if(sortedListX.size()==2) //如果只有两个元素 76 return dist(sortedListX.get(0),sortedListX.get(1)); 77 78 else{ //大于2个元素 79 int mid=sortedListX.size()/2; //在第mid个点处把点分成左右相等的两部分 80 double L=sortedListX.get(mid).getX(); //把点分成左右相等的两部分的直线的横坐标,设这条直线为L 81 82 //L左边的点的横坐标升序排序的数组 83 List<Point> sortedListXL=sortedListX.subList(0, mid); 84 85 //L右边的点的横坐标升序排序的数组 86 List<Point> sortedListXR=sortedListX.subList(mid, sortedListX.size()); 87 88 List<Point> sortedListYL=new ArrayList<>(); //L左边的点的纵坐标升序排序的数组 89 List<Point> sortedListYR=new ArrayList<>(); //L右边的点的纵坐标升序排序的数组 90 91 //求sortedListYL与sortedListYR 92 for(int i=0;i<sortedListY.size();i++){ 93 Point p=sortedListY.get(i); 94 if(sortedListY.get(i).getX()<L){ 95 sortedListYL.add(p); 96 }else{ 97 sortedListYR.add(p); 98 } 99 } 100 101 double dL=divide(sortedListXL,sortedListYL); //L左边两个点之间的最短距离 102 double dR=divide(sortedListXR,sortedListYR); //L右边两个点之间的最短距离 103 104 //比较L左边最短距离、L右边最短距离以及跨越L的顶点对之间的最短距离 105 return conquer(sortedListY,L,Math.min(dL, dR)); 106 }//else 107 } 108 109 //子问题解的合并 110 public static double conquer(List<Point> sortedListY,double L,double d){ 111 //求在L-d以及L+d之间的顶点(2d-strip) 112 List<Point> inside2DList=new ArrayList<>(); 113 for(int i=0;i<sortedListY.size();i++){ 114 Point p=sortedListY.get(i); 115 if(p.getX()>L-d || p.getX()<L+d){ 116 inside2DList.add(p); 117 } 118 } 119 120 //求2d-strip之间顶点对的最短距离、与L左边和右边的最短距离比较,最小者为最终结果 121 double minDistance=d; 122 for(int i=0;i<inside2DList.size()-1;i++){ 123 //i只需与i之后的11个顶点比较,i与大于11个顶点之后的顶点的距离一定大于等于d 124 for(int j=i+1;j<=i+11 && j<inside2DList.size();j++){ 125 double temp=dist(inside2DList.get(i),inside2DList.get(j)); 126 if(temp<minDistance) 127 minDistance=temp; 128 } 129 } 130 return minDistance; 131 } 132 133 //计算两点之间的距离 134 public static double dist(Point a,Point b){ 135 return Math.sqrt(Math.pow(a.getX()-b.getX(), 2)+Math.pow(a.getY()-b.getY(), 2)); 136 } 137 138 //蛮力法 139 public static double bruteforce(List<Point> pointList){ 140 double minDistance=Double.MAX_VALUE; 141 //依次比较每个顶点对 142 for(int i=0;i<pointList.size();i++){ 143 for(int j=i+1;j<pointList.size();j++){ 144 double temp=dist(pointList.get(i),pointList.get(j)); 145 if(temp<minDistance) 146 minDistance=temp; 147 } 148 } 149 return minDistance; 150 } 151 } 152 153 class Point{ 154 private double x; //横坐标 155 private double y; //纵坐标 156 157 public Point(int x,int y){ 158 this.x=x; 159 this.y=y; 160 } 161 162 public double getX() { 163 return x; 164 } 165 166 public void setX(double x) { 167 this.x = x; 168 } 169 170 public double getY() { 171 return y; 172 } 173 174 public void setY(double y) { 175 this.y = y; 176 } 177 178 public String toString(){ 179 return x+","+y; 180 } 181 }