1)算法描述:
1.分割:将集合S进行以垂直于x轴的直线L进行平均划分,并且保证SL和SR中的点数目各为n/2,
(否则以其他方式划分S,有可能导致SL和SR中点数目一个为1,一个为n-1,不利于算法效率,要尽量保持树的平衡性)
依次找出这两部分中的最小点对距离:δL和δR,记SL和SR中最小点对距离δ = min(δL,δR),如图1:
2.查找边界附近距离小于δ的点对: 以L为中心,δ为半径划分一个长带,最小点对还有可能存在于SL和SR的交界处,如下图2左图中的虚线带,p点和q点分别位于SL和SR的虚线范围内,在这个范围内,p点和q点之间的距离才会小于δ,最小点对计算才有意义。
又因为虚线内的点可能比较多,因此不可能全部进行距离比较,因此对数据的y轴也进行划分,两条垂直于y轴的直线距离p为+-δ,这样就得到了一个矩形,只需将p与矩形内的点进行比较即可(矩形外的点与p的距离一定大于δ,没有比较的意义),且可以证明,矩形内的点最多为6个,因此点p最多与SR中的点比较6次即可。(因为最小距离为δ,要使矩形内的点的数量最多,则只有分布于两个正方形的六个顶点上,其他情况的点数全都一定小于6)
2) 代码描述:
1)对点集S的点x坐标和y坐标进行升序排序,获得点集Sx和Sy
2)令δ=∞; //δ为最小点位距离
3)Divide_conquer(Sx,Sy,δ) //分治法
if (Sx.count=1) then δ=∞; //如果Sx中只有一个点,则δ=∞
return δ;
else if(Sx.count=2 and d(Sx.[0],Sx.[1])<δ) //如果Sx中只有2个点,则δ为两点之间距离
δ=d(Sx.[0],)Sx.[1]);
return δ;
else //如果Sx中多于2个点,则将Sx,Sy分治,以中心点画线,将Sx分为左右两部分SxL和SxR,Sy分为SyL和SyR
j1=1,j2=1,k1=1,k2=1;
mid = Sx.count/2; //mid为Sx中的中间点点号
L = Sx.[mid].x; //L为Sx中的中间点x坐标
for(i=1,i<Sx.count,i++)
{
if(i<=mid) //将Sx中间线以左地方的点存入到SxL,新数组保持原来的升序性质
SxL[k1] = Sx[i] k1++;
else //将Sx中间线以右的地方的点存入到SxR,新数组保持原来的升序性质
SxR.count[k2] = Sx[i] k2++;
if(Sy[i].x <L) //将Sy中间线以左地方的点存入到SyL,新数组保持原来的升序性质
SyL[j1] = Sx[i] j1++;
else //将Sy中间线以右地方的点存入到SyR,新数组保持原来的升序性质
SyR[j2] = Sx[i] j2++;
}
δL = Divide_conquer(SxL,SyL,δ); //获取Sx中的的最小点位距离δL
δR = Divide_conquer(SxR,SyR,δ); //获取Sy中的的最小点位距离δR
δ= min (δL,δR);
δ=merge(SyL,SyR,δ); //获Sx中Sy交界处的最小点位距离,并综合 δL和δR 求出点集的最小点位距离δ
return δ;
函数merge(SyL,SyR,δ)
merge(SyL,SyR,δ)
{
i1=1,i2=1;
for(i=1,i<SyL.count,i++) //获取SyL中在左边虚框(距离小于δ)内的点,存入到S'yL中,新数组保持原来的升序性质
{
if(SyL[i].x>L-δ)
then S'yL[i1]= SyL[i], i1++,
}
for(i=1,i<SyR.count,i++) //获取SyR中在右边虚框(距离小于δ)内的点,存入到S'yR中,新数组保持原来的升序性质
{
if(SyR[i].x<L+δ)
then S'yR[i2]= SyR[i], i2++,
}
t=1;
for(i=1,i<S'yL.count,i++)
{
while(S'yR[t].y< S'yL[t].y and t < SyR.count) //获取点集S'yR内距离点S'yL[t]y坐标最接近的点号
{ t++; }
for( j= max(1,t-3), j<=min(t+3,S'yR.count),j++) //计算S'yR中的点与S'yL[t]y坐标相邻的六个点的距离
{
if(d(S'yL[i],S'yL[j])<δ) //如果前两点之间距离小于δ
then δ = d(S'yL[i],S'yL[j]); //则最小点位距离δ为当前两点之间距离
}
return δ
}
3)算法时间复杂度:
首先对点集S的点x坐标和y坐标进行升序排序,需要循环2nlogn次,复杂度为O(2nlogn)
接下来在分治过程中,对于每个S'yL中的点,都需要与S'yR中的6个点进行比较
O(n)= 2O(n/2) + (n/2)*6 (一个点集划分为左右两个点集,时间复杂度为左右两个点集加上中间区域运算之和)
其解为O(n)< O(3nlogn)
因此总的时间复杂度为O(3nlogn),比蛮力法的O(n2)要高效。