0007算法笔记——【分治法】最接近点对问题
0007算法笔记——【分治法】最接近点对问题

问题场景:在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。
在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。
例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看待,则具有最大碰撞危险的2架飞机,就是这个空间中最接近的一对点。
这类问题是计算几何学中研究的基本问题之一。
问题描述:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。
严格地说,最接近点对可能多于1对。
为了简单起见,这里只限于找其中的一对。
1、一维最接近点对问题算法思路:这个问题很容易理解,似乎也不难解决。
我们只要将每一点与其他n-1个点的距离算出,找出达到最小距离的两个点即可。
然而,这样做效率太低,需要O(n^2)的计算时间。
在问题的计算复杂性中我们可以看到,该问题的计算时间下界为Ω(nlogn)。
这个下界引导我们去找问题的一个θ(nlogn)算法。
采用分治法思想,考虑将所给的n个点的集合S分成2个子集S1和S2,每个子集中约有n/2个点,然后在每个子集中递归地求其最接近的点对。
在这里,一个关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对,因为S1和S2的最接近点对未必就是S 的最接近点对。
如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。
但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n^2/4次计算和比较才能确定S的最接近点对。
因此,依此思路,合并步骤耗时为O(n^2)。
整个算法所需计算时间T(n)应满足:T(n)=2T(n/2)+O(n^2)。
它的解为T(n)=O(n^2),即与合并步骤的耗时同阶,这不比用穷举的方法好。
从解递归方程的套用公式法,我们看到问题出在合并步骤耗时太多。
这启发我们把注意力放在合并步骤上。
设S中的n个点为x轴上的n个实数x1,x2,..,xn。
最接近点对问题教材

S2中的q3组成,则p3和q3一定在划分平面 L的距离d内。
第二步筛选:考虑P1中任意一点p,它若与
P2中的点q构成最接近点对的候选者,则必 有distance(p,q)<d。满足这个条件的P2 中的点定落在一个d×2d×2d的长方体R中
重要观察结论:P2中任何2个S中的点的距离 都不小于d。由此可以推出长方体R中最多只有 24个S中的点。
分治法解决二维空间最接近点问题
选取一垂直线l:x=m来作为分割直线。其中m为S中各 点x坐标的中位数。由此将S分割为S1和S2。 递归地在S1和S2上找出其最小距离d1和d2,并设 d=min{d1,d2},S中的最接近点对或者是d,或者是某个 {p,q},其中p∈S1且q∈S2。
第一步筛选:如果最近点对由S1中的p3和
4、设P1是S1中距垂直分割线l的距离在dm之 内的所有点组成的集合; { P2是S2中距分割线l的距离在dm之内所有 n=|S|; 点组成的集合; O(n) 将 P1 和 P2 中点依其 y 坐标值排序; if (n < 2) return ; 并设X和Y是相应的已排好序的点列; 1、m=S中各点x间坐标的中位数; 5、通过扫描X以及对于X中每个点检查Y中与 构造S1和S2; 其距离在dm之内的所有点(最多6个)可以完成 O(n) 合并; O(n) //S1={p∈S|x(p)<=m}, 当X中的扫描指针逐次向上移动时,Y中的 S2={p∈S|x(p)>m} 扫描指针可在宽为2dm的区间内移动; 2、d1=cpair2(S1); 设dl是按这种扫描方式找到的点对间的最 2T(n/2 小距离; d2=cpair2(S2); ) 6、d=min(dm,dl); 常数时间 3、dm=min(d1,d2); return d; 常数时间 }
最接近点对问题

一、最接近点对问题(一维)一、最接近点对问题(一维)最接近点对问题:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。
此时S中的n个点退化为x轴上的n个实数x1,x2,..,x n。
最接近点对即为这n个实数中相差最小的2个实数。
2、分析将所给的平面上n个点的集合S分成2个子集S1和S2,每一个子集中约有n/2个点,·然后在每一个子集中递归地求其最接近的点对。
S1和S2的最接近点对未必就是S的最接近点对,若是组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。
可是,若是这2个点别离在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它组成最接近点对的候选者,仍需做n2/4次计算和比较才能肯定S的最接近点对。
因此,依此思路,归并步骤耗时为O(n2)。
整个算法所需计算时间T(n)应知足:T(n)=2T(n/2)+O(n2)它的解为T(n)=O(n2)3、伪代码随机Randomfloat Random(){float result=rand()%10000;return result*;}返回最大、最小float Max OR Min(float s[],int p,intq)序实现#include<>#include<iostream>#include<cmath>using namespace std;const int M=50;D=i;X[i].x=Random();X[i].y=Random();c out<<"("<<X[i].x<<","<<X[i].y<<") ";}PointX a;PointX b;float d;Cpair2(X,number_used,a,b,d);cout<<endl;cout<<"the closest pair is ("<<<<","<<<<")和("<<<<","<<<<") "<<endl;cout<<"the min distance is "<<d<<endl;return 0;}float Random(){float result=rand()%10000;return result*;}=i;Y[i].x=X[i].x;Y[i].y=X[i].y;}PointY*tmpy=new PointY[n];MergeSort(Y,tmpy,0,n-1);PointY*Z=new PointY[n];closest(X,Y,Z,0,n-1,a,b,d);delete []Y;delete []Z;return true;}void closest(PointX X[],PointY Y[],PointY Z[], int l, int r,PointX& a,PointX& b,float& d){i f(r-l==1){>m) Z[g++]=Y[i];else Z[f++]=Y[i]; closest(X,Z,Y,l,m,a,b,d);float dr;PointX ar,br;closest(X,Z,Y,m+1,r,ar,br,dr);if(dr<d){a=ar;b=br;d=dr;}Merge(Z,Y,l,m,r);-Y[t].x)<d){Z[k++]=Y[t];}-Z[s].y<d;j++){float dp=dis(Z[s],Z[j]);if(dp<d){d=dp;a=X[Z[i].p];b=X[Z[j].p];} } } }template <typename Type>void Merge(Type c[],Type d[], int l, int m, int r){i nt i=l,j=m+1,k=l;w hile((i<=m)&&(j<=r))if(c[i]<=c[j])d[k++]=c[i++];elsed[k++]=c[j++];if(i>m)for(int q=j;q<=r;q++)d[k++]=c[q];elsefor(int q=i;q<=m;q++)d[k++]=c[q];}template <typename Type>void MergeSort(Type a[], Type b[],int left, int right){ // a[]为待排序的数组,left,right为a数组的下标,b[]为临时存放排好序的临时数组i f(left<right){int i=(left+right)/2;//取中点MergeSort(a,b,left,i);MergeSort(a,b,i+1,right);Merge(a,b,left,i,right);//归并到数组bCopy(a,b,left,right);//复制回数组a }}template <typename Type>void Copy(Type a[],Type b[], int right,int left) {for(int i=right;i<=left;i++)a[i]=b[i];}运行情况:。
1007分治法(最近点对)

由此可得:
C11 C12 C 21 C 22
A11 B11 A12 B21 A11 B12 A12 B22 A21 B11 A22 B21 A21 B12 A22 B22
Strassen矩阵乘法
(1 ) C12 A11 AO B11 B12 n 2 C11 T ( 12 n) 2 C 7 T ( n / 2 ) O ( n ) n2 C A A B B 22 22 21 22 21 21 M 1 A11 ( B12 B22 ) T(n)=O(nlog7) =O(n2.81)较大的改进 C11 M 5 M 4 M 2 M 6 M 2 ( A11 A12 ) B22
规模较小的情况
n=2
规模较小的情况
n=4
规模较小的情况
n=4
规模较小的情况
n=8
规模较小的情况
n=8
规模较大的情况
当k>0时,将2k×2k棋盘分割为4个2k-1×2k-1 子棋盘(a)所示。 特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特 殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘, 可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如 (b)所 示,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归 地使用这种分割,直至棋盘简化为棋盘1×1。
Strassen矩阵乘法
传统方法:O(n3)
A和B的乘积矩阵C中的元素C[i,j]定义为:C[i][ j ] A[i][ k ]B[k ][ j ]
k 1 n
若依此定义来计算A和B的乘积矩阵C,则每计 算C的一个元素C[i][j],需要做n次乘法和n-1次 加法。因此,算出矩阵C的 个元素所需的计算 时间为O(n3)
最近点对问题

最近点对问题I.一维问题:一、问题描述和分析最近点对问题的提法是:给定平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。
严格的讲,最接近点对可能多于1对,为简单起见,只找其中的1对作为问题的解。
简单的说,只要将每一点与其它n-1个点的距离算出,找出达到最小距离的2点即可。
但这样效率太低,故想到分治法来解决这个问题。
也就是说,将所给的平面上n个点的集合S 分成2个子集S1和S2,每个子集中约有n/2个点。
然后在每个子集中递归的求其最接近的点对。
这里,关键问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。
如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决,但如果这2个点分别在S1和S2中,问题就不那么简单了。
下面的基本算法中,将对其作具体分析。
二、基本算法假设用x轴上某个点m将S划分为2个集合S1和S2,使得S1={x∈S|x<=m};S2={x ∈S|x>m}。
因此,对于所有p∈S1和q∈S2有p<q。
递归的在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设d=min{|p1-p2|,|q1-q2|}。
由此易知,S中的最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{p3,q3},其中p3∈S1且q3∈S2。
如下图所示:S1 S2p1 p2 p3 q1 q2 q3图1 一维情形的分治法注意到,如果S的最接近点对是{p3,q3},即|p3-q3|<d,则p3和q3两者与m的距离不超过d,即|p3-m|<d,|q3-m|<d。
也就是说,p3∈(m-d,m],q3∈(m,m+d]。
由于每个长度为d的半闭区间至多包含S1中的一个点,并且m是S1和S2的分割点,因此(m-d,m]中至少包含一个S中的点。
同理,(m,m+d]中也至少包含一个S中的点。
平面最接近点对问题(分治法)

平⾯最接近点对问题(分治法)头⽂件部分:(1)数据结构部分://涉及的数据结构#ifndef DATASET_H#define DATASET_Hstruct point{ //点结构double x, y;};#endif(2)函数声明部分://函数头⽂件//=======================================#ifndef FUNC_H#define FUNC_H#include "dataset.h"double closest_distance(point s[], int low, int high, point rec[]);double Distance(point a, point b);bool comp_x(point a, point b);bool comp_y(point a, point b);#endif源⽂件部分:(1)函数实现部分://求解最近距离的函数实现#include "dataset.h"#include <math.h>#include <algorithm>using namespace std;double Distance(point a, point b) //计算两点距离{return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) - (a.y - b.y));}bool comp_x(point a, point b) //按x升序判别函数{return a.x < b.x;}bool comp_y(point a, point b) //按y升序判别函数{return a.y < b.y;}//函数实现:rec[]存储最接近点对;double closest_distance(point s[], int low, int high, point rec[]){double d1, d2, d3, d;int mid, i, j, index;double x1, y1, x2, y2; //记录最近的点对point *P = new point[high - low + 1];point temp_1[2], temp_2[2], temp_3[2];if (high - low == 1) //两个点时的情况{rec[0].x = s[low].x; rec[0].y = s[low].y;rec[1].x = s[high].x; rec[1].y = s[high].y;return Distance(s[low], s[high]);}if (high - low == 2) //三个点时的情况{d1 = Distance(s[low], s[low + 1]);d2 = Distance(s[low + 1], s[high]);d3 = Distance(s[low], s[high]);if ((d1 <= d2) && (d1 <= d3)) //这⾥在判断三种情况时,第⼆种情况没必要使⽤(d2<d3)&&(d2<d1),相较更繁琐了;{rec[0].x = s[low].x; rec[0].y = s[low].y;rec[1].x = s[low + 1].x; rec[1].y = s[low + 1].y;return d1;}else if (d2 < d3){rec[0].x = s[low + 1].x; rec[0].y = s[low + 1].y;rec[1].x = s[high].x; rec[1].y = s[high].y;return d2;}else{rec[0].x = s[low].x; rec[0].y = s[low].y;rec[1].x = s[high].x; rec[1].y = s[high].y;return d3;}}mid = (low + high) / 2;d1 = closest_distance(s, low, mid, rec);temp_1[0] = rec[0];temp_1[1] = rec[1];d2 = closest_distance(s, mid + 1 ,high, rec);temp_2[0] = rec[0];temp_2[1] = rec[1];if (d1 <= d2){d = d1;rec[0] = temp_1[0];rec[1] = temp_1[1];}else{d = d2;rec[0] = temp_2[0];rec[1] = temp_2[1];}index = 0;for (i = mid; (i >= low) && ((s[mid].x - s[i].x) < d); i--){P[index++] = s[i]; //点集合P1}for (i = mid + 1; (i <= high) && ((s[i].x - s[mid].x) < d); i++){P[index++] = s[i]; //点集合P2}sort(P, P + index, comp_y); //升序排列for (i = 0; i < index; i++){for (j = i + 1; j < index; j++){if ((P[j].y - P[i].y) >= d)break;else{d3 = Distance(P[i], P[j]);if (d3 < d){rec[0].x = P[i].x; rec[0].y = P[i].y;rec[1].x = P[j].x; rec[1].y = P[j].y;d = d3;}}}}delete []P; //注意动态内存的删除⽅式,防⽌内存泄漏return d;}(2)主函数部分://2018_02_24//使⽤分治法求解⼆维平⾯最接近点问题//============================================================= #include <iostream>#include <math.h>#include <algorithm>#include "dataset.h"//数据结构实现放在这个头⽂件中#include "func.h"//函数声明的头⽂件using namespace std;int main(void){point p[10]; //设定点的集合int n;double minDist;cout << "输⼊点的个数:\n";cin >> n;cout << "输⼊点集:(x , y) \n";for (int i = 0; i < n; i++)cin >> p[i].x >> p[i].y;sort(p, p + n, comp_x); //对输⼊的点先进⾏排序point index[2];minDist = closest_distance(p, 0, n - 1, index);cout << "最⼩距离点对为:(" << index[0].x << "," << index[0].y << "),(" << index[1].x << "," << index[1].y << ")"; cout << "最⼩距离为:\n" << minDist;system("pause");return0;}最后,结果如下:。
分治算法知识点总结

分治算法知识点总结一、基本概念分治算法是一种递归的算法,其基本思想就是将原问题分解成多个相互独立的子问题,然后分别解决这些子问题,最后将子问题的解合并得到原问题的解。
分治算法的核心思想可以用一句话概括:分而治之,分即是将原问题分解成若干个规模较小的子问题,治即是解决这些子问题,然后将子问题的解合并起来得到原问题的解。
分治算法通常包括三个步骤:(1)分解:将原问题分解成若干个规模较小的子问题;(2)解决:递归地解决这些子问题;(3)合并:将子问题的解合并起来得到原问题的解。
分治算法的典型特征包括递归和合并。
递归指的是将原问题分解成若干个规模较小的子问题,然后递归地解决这些子问题;合并指的是将子问题的解合并得到原问题的解。
通常来说,分治算法的递归实现方式很容易编写,但有时可能会面临大量的重复计算,因此需要合并操作来避免这种情况。
二、原理分治算法的原理可以通过一个简单的例子来说明。
我们以计算数组中的最大值为例,具体的步骤如下:(1)分解:将数组分解成两个规模相等的子数组;(2)解决:递归地在这两个子数组中分别找到最大值;(3)合并:比较这两个子数组的最大值,得到原数组的最大值。
从这个例子可以看出,分治算法将原问题分解成两个子问题:分别在左边子数组和右边子数组中找到最大值,然后将这两个子问题的解合并起来得到原数组的最大值。
这种将问题分解成若干个规模较小的子问题,然后合并子问题的解得到原问题的解的方法正是分治算法的核心原理。
分治算法的优势在于它可以将原问题分解成多个规模较小的子问题,然后并行地解决这些子问题,最后合并子问题的解得到原问题的解。
这种并行的设计思路使得分治算法非常适合于并行计算,能够有效地提高计算效率。
三、应用分治算法在计算机科学领域有着广泛的应用,包括排序、搜索、图论、动态规划等多个方面。
下面我们将以排序算法和搜索算法为例,来介绍分治算法在实际应用中的具体情况。
1. 排序算法排序算法是计算机科学领域中一个重要的问题,分治算法在排序算法中有着广泛的应用。
分治法二(平面最近点对)

分治法⼆(平⾯最近点对)上篇⽂章介绍了分治法的概念和基本解题步骤,并附加了⼀个例题帮助⼤家了解分治法的基本思想,在这篇⽂章中,我将对分治法的另⼀个经典问题进⾏分析,希望我的⽂章能够将今天的主题解释清楚。
接下来我将⽤三种不同的⽅法求解“平⾯最近点对”问题。
问题描述:在⼀个平⾯上随机分布着 n 个点,现给定 n 个点的坐标,要求给出最近的两个点之间的距离。
⽅法⼀:原始⽅法题⽬要求求出最近的两点之间的距离,先整理⼀下已知的线索:⾸先点的总个数为 n ;其次已知 n 个点的坐标。
掌握了每个点的坐标,就相当于间接地掌握了任意两点之间的距离。
假设两个点为 A : ( x1 , y1 ) , B : ( x2 , y2 ) ,两点间的距离为 distance ,根据平⾯坐标系中的两点间距离公式可得:distance ^ 2 = ( x1 - x2 ) ^ 2 + ( y1 - y2 ) ^ 2,运⽤该公式对每两个点的距离进⾏计算,并不断更新最⼩值 min_distance 。
核⼼代码为:这个⽅法很直观也最容易想到,不过,由以上的两层循环可知,该⽅法的时间复杂度为 o ( n ^ 2 ) ,当 n 的值不断增⼤时,这个⽅法处理起来就显得⼒不从⼼了。
因此我们必须寻找另⼀种更有效的⽅法,或者在此⽅法上进⾏适当的改进。
接下来⼀起了解⼀下第⼆种⽅法--分治法⽅法⼆:分治法为了做到有理有据,正式叙述解法之前,我得再啰嗦⼏句选择分治法的原因,希望不会引起⼤家的反感。
在本问题中,需要求得最近两点之间的距离,整个问题的规模为 n 个点,不妨将这 n 个点⼀分为⼆,就变成两个求解 n /2 个点规模下最近点对的距离问题,如此不断缩⼩规模,当变成两个点的规模下求解最近点对问题时,显⽽易见,即为这两个点的距离,这样随着问题规模的缩⼩解决的难易程度逐渐降低的特征正是可以⽤分治法解答的问题所具备的特征。
接下来,我们按照分治法解题步骤分割--求解--合并分析这个问题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
问题场景:在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。
在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。
例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看待,则具有最大碰撞危险的2架飞机,就是这个空间中最接近的一对点。
这类问题是计算几何学中研究的基本问题之一。
问题描述:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。
严格地说,最接近点对可能多于1对。
为了简单起见,这里只限于找其中的一对。
1、一维最接近点对问题算法思路:这个问题很容易理解,似乎也不难解决。
我们只要将每一点与其他n-1个点的距离算出,找出达到最小距离的两个点即可。
然而,这样做效率太低,需要O(n^2)的计算时间。
在问题的计算复杂性中我们可以看到,该问题的计算时间下界为Ω(nlogn)。
这个下界引导我们去找问题的一个θ(nlogn)算法。
采用分治法思想,考虑将所给的n个点的集合S分成2个子集S1和S2,每个子集中约有n/2个点,然后在每个子集中递归地求其最接近的点对。
在这里,一个关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对,因为S1和S2的最接近点对未必就是S的最接近点对。
如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。
但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n^2/4次计算和比较才能确定S的最接近点对。
因此,依此思路,合并步骤耗时为O(n^2)。
整个算法所需计算时间T(n)应满足:T(n)=2T(n/2)+O(n^2)。
它的解为T(n)=O(n^2),即与合并步骤的耗时同阶,这不比用穷举的方法好。
从解递归方程的套用公式法,我们看到问题出在合并步骤耗时太多。
这启发我们把注意力放在合并步骤上。
设S中的n个点为x轴上的n个实数x1,x2,..,xn。
最接近点对即为这n个实数中相差最小的2个实数。
我们显然可以先将x1,x2,..,xn排好序,然后,用一次线性扫描就可以找出最接近点对。
这种方法主要计算时间花在排序上,在排序算法已经证明,时间复杂度为O(nlogn)。
然而这种方法无法直接推广到二维的情形。
因此,对这种一维的简单情形,我们还是尝试用分治法来求解,并希望能推广到二维的情形。
假设我们用x轴上某个点m将S划分为2个子集S1和S2,使得S1={x∈S|x≤m};S2={x∈S|x>m}。
这样一来,对于所有p∈S1和q∈S2有p<q。
递归地在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设d=min{|p1-p2|,|q1-q2|},S中的最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{p3,q3},其中p3∈S1且q3∈S2。
如图所示。
页脚内容1如果S的最接近点对是{p3,q3},即|p3-q3|<d,则p3和q3两者与m的距离不超过d,即|p3-m|<d,|q3-m|<d,也就是说,p3∈(m-d,m],q3∈(m,m+d]。
由于在S1中,每个长度为d的半闭区间至多包含一个点(否则必有两点距离小于d),并且m是S1和S2的分割点,因此(m-d,m]中至多包含S中的一个点。
同理,(m,m+d]中也至多包含S中的一个点。
由图可以看出,如果(m-d,m]中有S中的点,则此点就是S1中最大点。
同理,如果(m,m+d]中有S中的点,则此点就是S2中最小点。
因此,我们用线性时间就能找到区间(m-d,m]和(m,m+d]中所有点,即p3和q3。
从而我们用线性时间就可以将S1的解和S2的解合并成为S的解。
也就是说,按这种分治策略,合并步可在O(n)时间内完成。
这样是否就可以得到一个有效的算法了呢?还有一个问题需要认真考虑,即分割点m的选取,及S1和S2的划分。
选取分割点m的一个基本要求是由此导出集合S的一个线性分割,即S=S1∪S2 ,S1∩S2=Φ,且S1={x|x≤m};S2={x|x>m}。
容易看出,如果选取m=[max(S)+min(S)]/2,可以满足线性分割的要求。
选取分割点后,再用O(n)时间即可将S划分成S1={x∈S|x≤m}和S2={x∈S|x>m}。
然而,这样选取分割点m,有可能造成划分出的子集S1和S2的不平衡。
例如在最坏情况下,|S1|=1,|S2|=n-1,由此产生的分治法在最坏情况下所需的计算时间T(n)应满足递归方程:T(n)=T(n-1)+O(n)它的解是T(n)=O(n^2)。
这种效率降低的现象可以通过分治法中“平衡子问题”的方法加以解决。
即通过适当选择分割点m,使S1和S2中有大致相等个数的点。
自然地,我们会想到用S的n个点的坐标的中位数来作分割点。
在选择算法中介绍的选取中位数的线性时间算法使我们可以在O(n)时间内确定一个平衡的分割点m。
本程序确定平衡点采用m=[max(S)+min(S)]/2方法。
如果需要利用中位数作分割点,看结合笔者博文《0005算法笔记——线性时间选择》改写。
一维最接近临近点对问题程序清单如下:[cpp]viewplain copy1.//2d10-1 一维最邻近点对问题2.#includ e "stdafx.h"3.#includ e <ctime>4.#includ e <iostream>页脚内容2ing namespace std;6.const int L=100;7.//点对结构体8.struct Pair9.{10.fl oat d;//点对距离11.fl oat d1,d2;//点对坐标12.};13.fl oat Rand om();14.int input(fl oat s[]);//构造S15.fl oat Max(fl oat s[],int p,int q);16.fl oat Min(fl oat s[],int p,int q);17.template <class Type>18.void Swap(Type &x,Type &y);19.template <class Type>20.int Partition(Type s[],Type x,int l,int r);21.Pair Cpair(fl oat s[],int l,int r);22.int main()23.{24. srand((unsigned)time(NULL));页脚内容325.int m;26.fl oat s[L];27. Pair d;28. m=input(s);29. d=Cpair(s,0,m-1);30. cout<<endl<<"最近点对坐标为: (d1:"<<d.d1<<",d2:"<<d.d2<<")";31. cout<<endl<<"这两点距离为: "<<d.d<<endl;32.return 0;33.}34.fl oat Rand om()35.{36.fl oat result=rand()%10000;37.return result*0.01;38.}39.int input(fl oat s[])40.{41.int l ength;42. cout<<"输入点的数目: ";43. cin>>length;44. cout<<"点集在X轴上坐标为:";页脚内容445.for(int i=0;i<l ength;i++)46. {47. s[i]=Rand om();48. cout<<s[i]<<" ";49. }50.return l ength;51.}52.fl oat Max(fl oat s[],int l,int r)//返回s[]中的最大值53.{54.fl oat s_max=s[l];55.for(int i=l+1;i<=r;i++)56.if(s_max<s[i])57. s_max=s[i];58.return s_max;59.}60.fl oat Min(fl oat s[],int l,int r)//返回s[]中的最小值61.{62.fl oat s_min=s[l];63.for(int i=l+1;i<=r;i++)64.if(s_min>s[i])页脚内容565. s_min=s[i];66.return s_min;67.}68.template <class Type>69.void Swap(Type &x,Type &y)70.{71. Type temp = x;72. x = y;73. y = temp;74.}75.template <class Type>76.int Partition(Type s[],Type x,int l,int r)77.{78.int i = l - 1,j = r + 1;79.whil e(true)80. {81.whil e(s[++i]<x && i<r);82.whil e(s[--j]>x);83.if(i>=j)84. {页脚内容685.break;86. }87. Swap(s[i],s[j]);88. }89.return j;90.}91.//返回s[]中的具有最近距离的点对及其距离92.Pair Cpair(fl oat s[],int l,int r)93.{94. Pair min_d={99999,0,0};//最短距离95.if(r-l<1) return min_d;96.fl oat m1=Max(s,l,r),m2=Min(s,l,r);97.fl oat m=(m1+m2)/2;//找出点集中的中位数98.//将点集中的各元素按与m的大小关系分组99.int j = Partition(s,m,l,r);100. Pair d1=Cpair(s,l,j),d2=Cpair(s,j+1,r);//递归101.fl oat p=Max(s,l,j),q=Min(s,j+1,r);102.//返回s[]中的具有最近距离的点对及其距离103.if(d1.d<d2.d)104. {页脚内容7105.if((q-p)<d1.d)106. {107. min_d.d=(q-p);108. min_d.d1=q;109. min_d.d2=p;110.return min_d;111. }112.else return d1;113. }114.else115. {116.if((q-p)<d2.d)117. {118. min_d.d=(q-p);119. min_d.d1=q;120. min_d.d2=p;121.return min_d;122. }123.else return d2;124. }页脚内容8125.}程序运行结果如下:该算法的分割步骤和合并步骤总共耗时O(n)。