首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >分治法求最近点对问题

分治法求最近点对问题

作者头像
叶茂林
发布2023-07-30 15:02:27
发布2023-07-30 15:02:27
32500
代码可运行
举报
运行总次数:0
代码可运行

蛮力法

  • 算法思想

蛮力法,顾名思义,即穷举所有点与点之间的距离,两层循环暴力找出最近点对。算法执行可视化如图1所示,word文档GIF静态显示,附件已含动图。

图1

  • 伪代码

matlab代码

代码语言:javascript
代码运行次数:0
运行
复制
result=[];
for power=1:10
    scale=power*100000;
    count=0;
    for times=1:20
        x=randi(scale,1,scale);
        y=randi(scale,1,scale);
        tic;
        [i,j]=brute(x,y,scale);
        count=count+toc;           
    end
    count=count/20;
    result=[result,count];
end
function [mini,minj]=brute(x,y,scale)
    mini=1;
    minj=1;
    minDistance=Inf;
    for i=1:scale-1
        for j=1:scale
            if i==j
                break
            end
            distance=(x(i)-x(j))^2+(y(i)-y(j))^2;
            if distance<minDistance
                mini=i;
                minj=j;
                minDistance=distance;
            end
        end
    end
end
  • 实验结果

环境为MATLAB,数据规模为1w到5w,运行结果如图2所示。

图2

具体数据如表1所示。

表1

分析:

由实验结果可知,蛮力法的实验值与理论值基本一致,算法的时间复杂度确实为O(n2),确实很慢。

分治法

  • 算法思想

先对点进行预处理按横坐标排序,然后每次将点均分成左右两个子集,最短距离的两个点要么都在左子集,要么都在右子集,要么一个点在左子集中,一个点在右子集中,对于前面两种情况,问题变成递归寻找子集的最短距离,算法执行可视化如图3所示,word文档GIF静态显示,附件已含动图。

图3

而对于跨越中间线的情况,由左右两个子集可以算出一个目前最短距离minDistance,然后将距离中间点的距离小于minDistance的点找出来,如图4所示。

图4

如果存在最短距离,那么一定是一边一个点,所以我们需要将两边点的距离算一下,实际上,我们需要对于一边的点,我们需要计算距离的点最多不超过4个,因为同一边的点与点之间的距离肯定大于等于minDistance,所以对于另一边的点来说,范围小于minDistance内的点不会超过4个,如图5所示。

图5

  • 伪代码

matlab代

代码语言:javascript
代码运行次数:0
运行
复制
result=[];
for power=1:10
    scale=power*100000;
    count=0;
    for times=1:20
        x=randi(scale,1,scale);
        y=randi(scale,1,scale);
        tic;
        [x,y]=Quick(1,scale,x,y);
        [mini,minj,minDistance]=divide(x,y,scale);
        count=count+toc;           
    end
    count=count/20;
    result=[result,count];
end
function [mini,minj,minDistance]=brute(x,y,scale)
    mini=1;
    minj=2;
    minDistance=Inf;
    for i=1:scale-1
        for j=i+1:scale
            distance=(x(i)-x(j))^2+(y(i)-y(j))^2;
            if distance<minDistance
                mini=i;
                minj=j;
                minDistance=distance;
            end
        end
    end
end
function [mini,minj,minDistance]=divide(x,y,scale)
    if length(x)<3
        [mini,minj,minDistance]=brute(x,y,scale);
        return;
    end
    half=floor(scale/2);
    [i,j,minLeft]=divide(x(1:half),y(1:half),half);
    [ii,jj,minRight]=divide(x(half+1:scale),y(half+1:scale),scale-half);
    if minLeft<minRight
        minDistance=minLeft;
        mini=i;
        minj=j;
    else
        minDistance=minRight;
        mini=ii;
        minj=jj;
    end
    left=[];
    right=[];
    for i=half-1:-1:1
        if abs(x(i)-x(half))>=sqrt(minDistance)
            break
        end
        left=[left,i];
    end
    for i=half+1:scale
        if abs(x(i)-x(half))>=sqrt(minDistance)
            break
        end
        right=[right,i];
    end
    for i=1:length(left)
        for j=1:length(right)
            if j>3
                break
            end
            distance=(x(left(i))-x(right(j)))^2+(y(left(i))-y(right(j)))^2;
            if distance<minDistance
                mini=left(i);
                minj=right(j);
                minDistance=distance;
            end
        end
    end
    for i=1:length(right)
        for j=1:length(left)
            if j>3
                break
            end
            distance=(x(left(j))-x(right(i)))^2+(y(left(j))-y(right(i)))^2;
            if distance<minDistance
                mini=left(j);
                minj=right(i);
                minDistance=distance;
            end
        end
    end
end
function[x,y]=Quick(low,high,x,y)
    i=low;
    j=high;
    pivot=x(low);
    temp=y(low);
    while low<high
        while low<high&&pivot<=x(high)
            high=high-1;
        end
        if low<high
            x(low)=x(high);
            y(low)=y(high);
            low=low+1;
        end
        while low<high&&pivot>x(low)
            low=low+1;
        end
        if low<high
            x(high)=x(low);
            y(high)=y(low);
            high=high-1;
        end
    end
    x(low)=pivot;
    y(low)=temp;
    if i<low-1
        [x,y]=Quick(i,low-1,x,y);
    end
    if high+1<j
        [x,y]=Quick(high+1,j,x,y);
    end
end
  • 算法复杂度

对于数据规模为n的情况,二分的次数为log2n次,而计算跨中间线距离的时候计算次数小于3n,即此处的时间复杂度是线性的,即T(n)=T(n/2)+O(n),可算得T(n)=nlogn。

  • 实验结果

先在小规模数据上跑,环境为MATLAB,数据规模为1w到5w,运行结果如图6所示。

图6

具体数据如表2所示。

表2

数据规模为10w到100w,运行结果如图7所示。

图7

具体数据如表3所示。

表3

分析:

由实验结果可知,分治法明显远远快于蛮力法,小规模数据时实验值略小于理论值,大规模时实验值与理论值基本一致。

探究分治规模小于一定程度时采用暴力解法

由于分治时不断递归调用函数,程序开销较大,考虑当分治到数据规模小于一定程度时采用暴力解法的运行效果,数据规模为1w,参数设置100到1000测试,结果如图8所示。

图8

由实验结果可知,分治规模达到200时使用暴力效果最佳,将参数设置为200,在数据规模为1w到5w上与原始分治法对比,如图9所示。

图9

在数据规模为10w到100w上与原始分治法对比,如图10所示。

图10

分析:

由实验结果可知,在分治规模小于一定数量时采用暴力求解效率更快,特别是在数据规模大的时候,这种暴力分治相结合的方法相比原始分治法具有很大的优势。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 蛮力法
  • 分治法
  • 探究分治规模小于一定程度时采用暴力解法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档