zoukankan      html  css  js  c++  java
  • [算法]基于分区最近点算法的二维平面

    摘要:

    网上有关于寻找最近点的分而治之的方法很多讨论,但是,未完成的可执行代码,本文所介绍的问题一个完整的可执行代码,

    参考对于那些有兴趣。

    正文:

    作为对照。我们也同一时候实现了近期点对的枚举解法,详细的主函数例如以下:

    #include<stdio.h>
    #include<stdlib.h>
    #include "node.h"
    
    void initList(node* p)
    {
    		p[0].x= 2.0;
    		p[0].y= 1.0;
    
    		p[1].x= 1.0;
    		p[1].y= 2.0;
    
    		p[2].x= 1.2;
    		p[2].y= 3.0;
    
    		p[3].x= 3.0;
    		p[3].y= 4.0;
    
    		p[4].x= 5.0;
    		p[4].y= 5.0;
    	
    		p[5].x= 1.5;
    		p[5].y= 5.5;
    
    		p[6].x= 2.5;
    		p[6].y= 7.0;
    
    		p[7].x= 3.5;
    		p[7].y= 8.0;
    
    		p[8].x= 4.0;
    		p[8].y= 9.0;
    
    		p[9].x = 3.9;
    		p[9].y = 8.8;
    }
    
    //測试分治和暴力;
    int main()
    {
    	node* p = (node*)malloc(sizeof(node)*10);
    	initList(p);
    
    	double ddf = force(p, 10); //9 is the number of elements;
    	printf("the output of force is %lf
    ", ddf);
    
    	double dd = callMinDist(p, 10);
    	printf("the output of divide-conquer is %lf
    ", dd);
    
    	getchar();
    	return 0;
    }
    上述中的force()是枚举的实现,callMinDist则是分治的实现。上述的initList主要对採用的測试案例进行初始化。

    以下是node.h头文件的相关代码:

    #ifndef __NODE__
    #define __NODE__
    
    #define SIZE 4
    #define MAX 100000.0
    
    typedef struct{
    	double x;
    	double y;
    }node;
    
    
    //排序部分;
    void mergeX(node a[], node b[], int s, int m, int t);
    void mergeY(node a[], node b[], int s, int m, int t);
    void mergeSortX(node a[], node b[], int s, int t);
    void mergeSortY(node a[], node b[], int s, int t);
    
    //utility;
    void show(node* a, int size);
    void initList(node* list);
    double dist(node* n1, node* n2);
    
    //枚举部分;
    double force(node* nodelist, int n);
    
    //分治部分;
    double combine(node* py, int n, double lx, double delta);
    void copynode(node* dt, node* sr, int b, int n);
    double minDist(node* px, node* py, int n);
    double callMinDist(node*p, int n);
    
    
    #endif

    枚举部分的代码比較简单。详细看例如以下:

    #include <math.h>
    #include "node.h"
    
    double dist(node* n1, node* n2)
    {
    	double temp1 = n1->x - n2->x;
    	double temp2 = n1->y - n2->y;
    
    	double sum = temp1*temp1 + temp2*temp2; //pow(temp1, 2)+pow(temp2, 2);
    	return sqrt(sum);
    }
    
    double force(node* nodelist, int n) //n is number of elements
    {
    	//这里d须要有一个初始的大值;
    	double d = MAX;
    	double t;
    	
    	//函数的主体就是以下这个双层循环;
    	for(int i=0; i<n; i++){
    		for(int j=i+1; j<n; j++)
    		{
    			t = dist(&nodelist[i], &nodelist[j]);
    			if(t<d)
    				d = t;
    		}
    	}
    	//这里最后返回d;
    	return d;
    }

    以下是对于分治算法的调用部分,调用之前须要分别将当中的点按x轴和按y轴进行排序操作,而且

    将排完序的点放置在新的存储空间中。

    double callMinDist(node* p, int n){
    
    	node* px = (node*)malloc(n*sizeof(node)); //n主要是用于此处的空间申请;
    	node* py = (node*)malloc(n*sizeof(node));
    
    	//show(p, n);
    	mergeSortX(p, px, 0, n-1); //按点的x轴值排序;
    	copynode(px, p, 0, n-1);
    	//show(px, n);
    
    	//show(p, n);
    	mergeSortY(p, py, 0, n-1); //按点的y轴值排序。
    	copynode(py, p, 0, n-1);
    	//show(py, n);
    
    	double min = minDist(px, py, n);
    
    	free(px);
    	free(py);
    
    	return min;
    }

    以下就是分治算法的主体:

    double minDist(node* px, node* py, int n)  //这里n是number of elements呢?还是max of index?依据以下的空间申请,应该是number of elements.
    {
    		//printf("n is %d
    ", n);
    		if(n<=3){
    			//show(px, n); //n is number of elements;
    			double d = force(px, n); //n is number of elements;
    			//printf("n=%d is %lf
    ",n, d);
    			return d;
    		}
    		
    		int m=n/2;
    		double fx = px[m].x;
    
    		node* lx = (node*)malloc(m*sizeof(node));
    		node* ly = (node*)malloc(m*sizeof(node));
    		node* rx = (node*)malloc((n-m)*sizeof(node));
    		node* ry = (node*)malloc((n-m)*sizeof(node));
    		
    		
    		copynode(lx, px, 0, m-1); //对copy而言,这里的m应该是index;
    		//show(lx, m);  //show中的n是number of elements;
    		//printf("lx :%x
    ", lx);
    
    		copynode(rx, px, m, n-1); //copy这边是index;
    		//show(rx, n-m);
    
    		copynode(ly, py, 0, m-1);
    		//show(ly, m);
    
    		copynode(ry, py, m, n-1);
    		//show(ry, n-m);
    		
    		double d1 = minDist(lx, ly, m); //m is number of elements;
    		double dr = minDist(rx, ry, n-m);
    		
    		double delta = min(d1, dr);
    		double d = combine(py, n, fx, delta); //对combine而言,这里的n是number of elements;
    
    		//printf("lx :%x
    ", lx);
    		free(lx);
    		free(ly);
    		free(rx);
    		free(ry);
    		
    		return min(delta, d);
    }

    通过dl = minDist(lx, ly, m)来完毕左半部分的计算;

    dr = minDist(rx, ry, n-m)完毕右半部分的计算。

    最后通过combine(py, n, fx, delta)将两半部分的结果整合在一起。

    这里的关键之处在于combine函数:

    double combine(node* py, int n, double lx, double delta)
    {
    	int num; double d=MAX;
    	double tempd;
    	node* temp = (node*)malloc(n*sizeof(node));
    
    	int j=0;
    
    	for(int i=0; i<n; i++)
    	{
    		if(fabs(py[i].x - lx)<= delta){ //求取在区间范围内的点;
    			temp[j].x = py[i].x;
    			temp[j].y = py[i].y;
    			j++;
    		}
    	}
    
    	num = j;  //temp中的元素
    
    	for(int i=0; i<num; i++)
    	{
    		for(j=i+1; j<(i+8) && (j<num); j++)
    		{
    			tempd = dist(&temp[i], &temp[j]);
    			if(tempd < d)
    				d=tempd;
    		}
    	}
    
    	free(temp);
    	return d;
    }
    依据书本上的分析。在区间中求取时,仅仅须要计算当前点后(按y轴的值排序)的6到7

    个点就可以,因此此处的语句表现为:

    for(j=i+1; j<(i+8)&&(j<num); j+)....

    最后。我们来看下上述代码中用到的一些周边函数:

    void copynode(node* dt, node* sr, int b, int n) //n is max of index;
    {
    	int k=0;
    
    	for(int i=b; i<=n; i++)
    	{
    		dt[k].x = sr[i].x;
    		dt[k].y = sr[i].y;
    		k++;
    	}
    }
    
    double min(double x, double y)
    {
    	if(x<=y)
    		return x;
    	return y;
    }

    还有是通过归并排序对点集中的点进行排序的过程:

    void mergeSortX(node a[], node b[], int s, int t)
    {
    	if(s == t){
    		b[s].x = a[s].x;
    		b[s].y = a[s].y;
    	}
    	else{
    		int m = (s+t)/2;
    		mergeSortX(a, b, s, m);
    		mergeSortX(a, b, m+1, t);
    		mergeX(a, b, s, m, t);
    	}
    }
    
    void mergeSortY(node a[], node b[], int s, int t)
    {
    	if(s == t){
    		b[s].x = a[s].x;
    		b[s].y = a[s].y;
    	}
    	else{
    		int m = (s+t)/2;
    		mergeSortY(a, b, s, m);
    		mergeSortY(a, b, m+1, t);
    		mergeY(a, b, s, m, t);
    	}
    }
    
    
    void mergeX(node* a, node* b, int s, int m, int t)
    {
    	int i, j, n;
    
    	for(i=s, j=m+1, n=s; (i<=m)&&(j<=t); n++){
    		if(b[i].x<=b[j].x){
    			a[n].x = b[i].x;
    			a[n].y = b[i].y;
    			i++;
    		}else{
    			a[n].x = b[j].x;
    			a[n].y = b[j].y;
    			j++;
    		}
    	}
    	while(i<=m){
    		a[n].x = b[i].x;
    		a[n++].y = b[i++].y;
    	}
    
    	while(j<=t){
    		a[n].x = b[j].x;
    		a[n++].y = b[j++].y;
    	}
    
    	//这里须要将a中的数据又一次复制到b中;
    	for(int i=s; i<=t; i++){
    		b[i].x = a[i].x;
    		b[i].y = a[i].y;
    	}
    }
    
    void mergeY(node* a, node* b, int s, int m, int t)
    {
    	int i, j, n;
    
    	for(i=s, j=m+1, n=s; (i<=m)&&(j<=t); n++){
    		if(b[i].y<=b[j].y){
    			a[n].x = b[i].x;
    			a[n].y = b[i].y;
    			i++;
    		}else{
    			a[n].x = b[j].x;
    			a[n].y = b[j].y;
    			j++;
    		}
    	}
    	while(i<=m){
    		a[n].x = b[i].x;
    		a[n++].y = b[i++].y;
    	}
    
    	while(j<=t){
    		a[n].x = b[j].x;
    		a[n++].y = b[j++].y;
    	}
    
    	//这里须要将a中的数据又一次复制到b中;
    	for(int i=s; i<=t; i++){
    		b[i].x = a[i].x;
    		b[i].y = a[i].y;
    	}
    }
    注意:上述的归并排序函数写得不好,不是必需用到a这个參数,全然能够函数内部堆上分配局部变量进行替换。另外代码中反复部分太多,应该能够写得更精简一点。

    结论:

    针对代码中的简单測试案例。分治案例结果正常;该算法的主要时间复杂度在于排序部分,复杂度为O(nlogn),的复杂性的版本号枚举O(n2)。



    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    小程序发展史
    ES6内置方法find 和 filter的区别在哪
    微信小程序开发踩坑记录
    小程序导航跳转一不小心踩进的坑
    谈谈如何对后台登陆界面进行渗透
    应急响应学习笔记
    php学习笔记
    代码审计学习笔记
    注入笔记(非sql注入)
    python安全编程学习
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4832480.html
Copyright © 2011-2022 走看看