Algs4-1.2.1编写一个Point2D的用例-分治法

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
参考资料:

图片

图片

图片

图片

图片

posted @ 2018-10-25 11:33  修电脑的龙生  阅读(496)  评论(0编辑  收藏  举报