Algs4-1.2.1編寫一個Point2D的用例-分治法
阿新 • • 發佈:2018-10-25
\n into class divide 治法 命令 完美 out stdout
代碼如下:
import java.util.Arrays;
import java.util.Comparator;
public class Test
{
private static double DistOfFinfinity;
private static class closestPairePoint
{
int Point1;
int Point2;
}
public static void main(String[] args)
{
int N=Integer.parseInt(args[0]);
double start=0;
double width=200;
DistOfFinfinity=2*width*width;
//generate points.
double x,y;
Point2D[] pointArray=new Point2D[N];
double[][] pX=new double[N][3];
double[][] pY=new double[N][3];
for(int i=0;i<N;i++)
{
x=StdRandom.uniform(start,width);
y=StdRandom.uniform(start,width);
pointArray[i]=new Point2D(x,y);
//
pX[i][0]=i;
pX[i][1]=x;
pX[i][2]=y;
}
// order pX by X asc
Arrays.sort(pX,new Comparator<double[]>() {
@Override
public int compare(double[] x, double[] y) {
if(x[1] > y[1]) return 1;
else if (x[1] < y[1]) return -1;
else
{
return 0;
}
}
});
for (int i=0;i<N;i++)
{
//
pY[i][0]=i;
pY[i][1]=pX[i][1];
pY[i][2]=pX[i][2];
}
// order pY by Y asc
Arrays.sort(pY,new Comparator<double[]>() {
@Override
public int compare(double[] x, double[] y) {
if(x[2] > y[2]) return 1;
else if (x[2] < y[2]) return -1;
else
{
return 0;
}
}
});
//find closest pair of point.
closestPairePoint closestPoint = new closestPairePoint();
closestPoint.Point1=-1;
closestPoint.Point2=-1;
double closestDist=DistOfFinfinity;
if (N==0)
{
StdOut.printf("No point!");
return;
}
else if (N==1)
{
StdOut.printf("Only one point!");
return;
}
else if (N<=3)
{
double dist;
for(int i=0;i<N;i++)
{
for(int j=i+1;j<N;j++)
{
dist=pointDist(pX[i][1],pX[i][2],pX[j][1],pX[j][2]);
if (closestDist>dist)
{
closestDist=dist;
closestPoint.Point1=i;
closestPoint.Point2=j;
}//end if
}//end for j
}//end for i
}// end if N<=3
else if(N>3)
{
closestDist = closestTwoPoint (pX,0,pX.length-1,pY, closestPoint);
}//end if N>3
//draw all points
StdDraw.setXscale(start,width);
StdDraw.setYscale(start,width);
StdDraw.setPenRadius(0.005);
for(int i=0;i<N;i++)
{
pointArray[i].draw();
}
//draw closestDist pair of points
StdOut.printf("closestPointOne=%d,closestPointTwo=%d", closestPoint.Point1, closestPoint.Point2);
StdDraw.setPenRadius(0.01);
StdDraw.setPenColor(StdDraw.RED);
closestPoint.Point1=(int)pX[ closestPoint.Point1][0];
closestPoint.Point2=(int)pX[ closestPoint.Point2][0];
pointArray[ closestPoint.Point1].draw();
pointArray[ closestPoint.Point2].draw();
}//end main
private static double closestTwoPoint(double[][] pX, int loX,int hiX,double[][] pY, closestPairePoint closestPoint)
{
double closestDist=DistOfFinfinity;
//return
if ((hiX-loX+1)<=3)
{
double dist;
for(int i=loX;i<=hiX;i++)
{
for(int j=i+1;j<=hiX;j++)
{
dist=pointDist(pX[i][1],pX[i][2],pX[j][1],pX[j][2]);
if (closestDist>dist)
{
closestDist=dist;
closestPoint.Point1=i;
closestPoint.Point2=j;
}//end if (closestDist>dist)
}//end for j
}//end for i
}//end if ((hi-lo+1)<4)
else
{
//divide
closestPairePoint closestPointLeft=new closestPairePoint();
closestPointLeft.Point1=-1;
closestPointLeft.Point2=-1;
closestPairePoint closestPointRigth=new closestPairePoint();
closestPointRigth.Point1=-1;
closestPointRigth.Point2=-1;
int midX=loX+(hiX-loX)/2;
double[][] pYLeft=new double[midX-loX+1][3];
double[][] pYRight=new double[hiX-midX][3];
int Yleft=0;
int Yright=0;
for (int i=0;i<pY.length;i++)
{
if ((int)pY[i][0]>=loX && (int)pY[i][0]<=midX)
{
// StdOut.printf("pYleft length=%d,Yleft=%d\n",pYLeft.length,Yleft);
pYLeft[Yleft][0]=pY[i][0];
pYLeft[Yleft][1]=pY[i][1];
pYLeft[Yleft][2]=pY[i][2];
Yleft++;
}
else
{
//StdOut.printf("pYleft length=%d,Yleft=%d\n",pYLeft.length,Yleft);
pYRight[Yright][0]=pY[i][0];
pYRight[Yright][1]=pY[i][1];
pYRight[Yright][2]=pY[i][2];
Yright++;
}
}//end divide pYLeft\pYRight
//find closest paire point from XLeft and XRight.
double closestDistLeft=closestTwoPoint(pX,loX,midX,pYLeft, closestPointLeft);
double closestDistRight=closestTwoPoint(pX,midX+1,hiX,pYRight, closestPointRigth);
if (closestDistLeft<closestDistRight)
{
closestDist= closestDistLeft;
closestPoint.Point1=closestPointLeft.Point1;
closestPoint.Point2=closestPointLeft.Point2;
}
else
{
closestDist =closestDistRight;
closestPoint.Point1=closestPointRigth.Point1;
closestPoint.Point2=closestPointRigth.Point2;
}//end find closest paire point from XLeft or XRight.
//generate Y‘ (is name pY2)
double[][] pY2=new double[pY.length][3];
int pY2Index=0;
for (int i=0;i<pY.length;i++)
{
if (Math.abs(pY[i][1]-pX[midX][1])<closestDist)
{
pY2[pY2Index][0]=pY[i][0];
pY2[pY2Index][1]=pY[i][1];
pY2[pY2Index][2]=pY[i][2];
pY2Index++;
}
}
//find closest paire point from XLeft and XRight.
double mergeDist;
for (int i=0;i<pY2Index;i++)
for (int j=i+1;j<pY2Index && j<i+8;j++)
{
mergeDist=pointDist(pY2[i][1],pY2[i][2],pY2[j][1],pY2[j][2]);
if (mergeDist<closestDist)
{
closestDist= mergeDist;
closestPoint.Point1=(int)pY2[i][0];
closestPoint.Point2=(int)pY2[j][0];
}
}
}//end else
return closestDist;
}//end closestTwoPoint
private static double pointDist (double x1,double y1,double x2,double y2)
{
return Math.sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
}//end class Test
參考資料:
1.2.1編寫一個Point2D的用例,從命令行接受一個整數N。在單位正方形中生成N個隨機點,然後計算兩點之間的最近距離。
解:采用分治法。參考資料《算法導論》中文版第三版。
代碼實現過程中不太好處理的地方是:為了在Y‘數組中只檢查後續7個點而又不在遞歸中對Y數組進行排序的部分,這就需要確保從排序好的Y數組在O(n)內獲取YLeft與YRight的有序數組。
處理的思路是將原始點集復制到數組X,在X中保存點坐標和原始點集數組的索引,然後對X數組按x坐標升序排序,然後再X的坐原和X的索引存入Y數組,再對Y數組的y坐標升序排序。在Y數組中保存X的索引是在O(n)時間區分YLeft與YRight的關鍵,不足之處是將int型索引存入到double數組元素中,從而過多的出現了類型轉換,希望有更完美的處理方案,如有請告之。
代碼如下:
import java.util.Arrays;
import java.util.Comparator;
public class Test
{
private static double DistOfFinfinity;
private static class closestPairePoint
{
int Point1;
int Point2;
}
public static void main(String[] args)
{
int N=Integer.parseInt(args[0]);
double start=0;
double width=200;
DistOfFinfinity=2*width*width;
//generate points.
double x,y;
Point2D[] pointArray=new Point2D[N];
double[][] pX=new double[N][3];
double[][] pY=new double[N][3];
for(int i=0;i<N;i++)
{
x=StdRandom.uniform(start,width);
y=StdRandom.uniform(start,width);
pointArray[i]=new Point2D(x,y);
//
pX[i][0]=i;
pX[i][1]=x;
pX[i][2]=y;
}
// order pX by X asc
Arrays.sort(pX,new Comparator<double[]>() {
@Override
public int compare(double[] x, double[] y) {
if(x[1] > y[1]) return 1;
else if (x[1] < y[1]) return -1;
else
{
return 0;
}
}
});
for (int i=0;i<N;i++)
{
//
pY[i][0]=i;
pY[i][1]=pX[i][1];
pY[i][2]=pX[i][2];
}
// order pY by Y asc
Arrays.sort(pY,new Comparator<double[]>() {
@Override
public int compare(double[] x, double[] y) {
if(x[2] > y[2]) return 1;
else if (x[2] < y[2]) return -1;
else
{
return 0;
}
}
});
//find closest pair of point.
closestPairePoint closestPoint = new closestPairePoint();
closestPoint.Point1=-1;
closestPoint.Point2=-1;
double closestDist=DistOfFinfinity;
if (N==0)
{
StdOut.printf("No point!");
return;
}
else if (N==1)
{
StdOut.printf("Only one point!");
return;
}
else if (N<=3)
{
double dist;
for(int i=0;i<N;i++)
{
for(int j=i+1;j<N;j++)
{
dist=pointDist(pX[i][1],pX[i][2],pX[j][1],pX[j][2]);
if (closestDist>dist)
{
closestDist=dist;
closestPoint.Point1=i;
closestPoint.Point2=j;
}//end if
}//end for j
}//end for i
}// end if N<=3
else if(N>3)
{
closestDist = closestTwoPoint (pX,0,pX.length-1,pY, closestPoint);
}//end if N>3
//draw all points
StdDraw.setXscale(start,width);
StdDraw.setYscale(start,width);
StdDraw.setPenRadius(0.005);
for(int i=0;i<N;i++)
{
pointArray[i].draw();
}
//draw closestDist pair of points
StdOut.printf("closestPointOne=%d,closestPointTwo=%d", closestPoint.Point1, closestPoint.Point2);
StdDraw.setPenRadius(0.01);
StdDraw.setPenColor(StdDraw.RED);
closestPoint.Point1=(int)pX[ closestPoint.Point1][0];
closestPoint.Point2=(int)pX[ closestPoint.Point2][0];
pointArray[ closestPoint.Point1].draw();
pointArray[ closestPoint.Point2].draw();
}//end main
private static double closestTwoPoint(double[][] pX, int loX,int hiX,double[][] pY, closestPairePoint closestPoint)
{
double closestDist=DistOfFinfinity;
//return
if ((hiX-loX+1)<=3)
{
double dist;
for(int i=loX;i<=hiX;i++)
{
for(int j=i+1;j<=hiX;j++)
{
dist=pointDist(pX[i][1],pX[i][2],pX[j][1],pX[j][2]);
if (closestDist>dist)
{
closestDist=dist;
closestPoint.Point1=i;
closestPoint.Point2=j;
}//end if (closestDist>dist)
}//end for j
}//end for i
}//end if ((hi-lo+1)<4)
else
{
//divide
closestPairePoint closestPointLeft=new closestPairePoint();
closestPointLeft.Point1=-1;
closestPointLeft.Point2=-1;
closestPairePoint closestPointRigth=new closestPairePoint();
closestPointRigth.Point1=-1;
closestPointRigth.Point2=-1;
int midX=loX+(hiX-loX)/2;
double[][] pYLeft=new double[midX-loX+1][3];
double[][] pYRight=new double[hiX-midX][3];
int Yleft=0;
int Yright=0;
for (int i=0;i<pY.length;i++)
{
if ((int)pY[i][0]>=loX && (int)pY[i][0]<=midX)
{
// StdOut.printf("pYleft length=%d,Yleft=%d\n",pYLeft.length,Yleft);
pYLeft[Yleft][0]=pY[i][0];
pYLeft[Yleft][1]=pY[i][1];
pYLeft[Yleft][2]=pY[i][2];
Yleft++;
}
else
{
//StdOut.printf("pYleft length=%d,Yleft=%d\n",pYLeft.length,Yleft);
pYRight[Yright][0]=pY[i][0];
pYRight[Yright][1]=pY[i][1];
pYRight[Yright][2]=pY[i][2];
Yright++;
}
}//end divide pYLeft\pYRight
//find closest paire point from XLeft and XRight.
double closestDistLeft=closestTwoPoint(pX,loX,midX,pYLeft, closestPointLeft);
double closestDistRight=closestTwoPoint(pX,midX+1,hiX,pYRight, closestPointRigth);
if (closestDistLeft<closestDistRight)
{
closestDist= closestDistLeft;
closestPoint.Point1=closestPointLeft.Point1;
closestPoint.Point2=closestPointLeft.Point2;
}
else
{
closestDist =closestDistRight;
closestPoint.Point1=closestPointRigth.Point1;
closestPoint.Point2=closestPointRigth.Point2;
}//end find closest paire point from XLeft or XRight.
//generate Y‘ (is name pY2)
double[][] pY2=new double[pY.length][3];
int pY2Index=0;
for (int i=0;i<pY.length;i++)
{
if (Math.abs(pY[i][1]-pX[midX][1])<closestDist)
{
pY2[pY2Index][0]=pY[i][0];
pY2[pY2Index][1]=pY[i][1];
pY2[pY2Index][2]=pY[i][2];
pY2Index++;
}
}
//find closest paire point from XLeft and XRight.
double mergeDist;
for (int i=0;i<pY2Index;i++)
for (int j=i+1;j<pY2Index && j<i+8;j++)
{
mergeDist=pointDist(pY2[i][1],pY2[i][2],pY2[j][1],pY2[j][2]);
if (mergeDist<closestDist)
{
closestDist= mergeDist;
closestPoint.Point1=(int)pY2[i][0];
closestPoint.Point2=(int)pY2[j][0];
}
}
}//end else
return closestDist;
}//end closestTwoPoint
private static double pointDist (double x1,double y1,double x2,double y2)
{
return Math.sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
}//end class Test
參考資料:
Algs4-1.2.1編寫一個Point2D的用例-分治法