分治法实现最近点对问题——C语言可视化

1. 分治法步骤

1.按x对点对数组进行从小到大排序
2.找出x中间值,按中间值划分数组为左右两部分
3.不断细分,找出左右两部分的最近点对
4.重复步骤1.2.3,得到最终左右两部分的最近点对的距离d
5.找出 |X - Xmid| < d ,部分的点对,此部分左边的点对集合我们设为p1,右边设为p2,对p1,p2中的点按y的大小从小到大排序
6.对P1中所有点p,对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者,对P1中每一点最多只要检查P2中排好序的相继6个点,具体证明见:这位仁兄的帖子

2.实现

头文件

#ifndef _CLOSESTPAIR_H_
#define _CLOSESTPAIR_H_

typedef struct Point
{
	int x;
	int y;
}Point;


void setPoints(Point points[], int pointsLength);
int Distance(Point point1, Point point2);
void sort(Point points[], int s, int e, char z);
void merge(Point points[], int s, int e, int mid, char z);
void divideByMid(int mid, Point points[], Point pointsL[], Point pointsR[], int n);
int getClosestInSides(Point points[], int pointsLength);
int getClosest(Point points[], Point result[2], int pointsLength);

#endif

C文件

#include "ClosestPair.h"
#include <graphics.h>
#include <stdio.h>
#include <math.h>
#include <time.h>

#define LENGTH 100
#define MYINFINITE 100000;

int main()
{  
	initgraph(960, 540);
	setcolor(WHITE);
	Point points[LENGTH] = { 0,0 };
	Point result[2] = { 0,0 };
	int distance = 0;
	setPoints(points, LENGTH);
	for (int i = 0; i < LENGTH; i++)
	{
		circle(points[i].x, points[i].y, 1);
	}
	distance = getClosest(points, result, LENGTH);
	setlinecolor(GREEN);
	line((int)result[0].x, (int)result[0].y, (int)result[1].x, (int)result[1].y);
	setcolor(RED);
	circle((int)result[0].x, (int)result[0].y, 1);
	circle((int)result[1].x, (int)result[1].y, 1);
	outtextxy(5, 5, "distance: ");
	char distanceText[20];
	_itoa_s(distance, distanceText, 10);
	outtextxy(70, 5, distanceText);
	system("pause");
	getchar();
	return 0;
}
//在画面生成内不重复的一定数量的点
void setPoints(Point points[],int pointsLength)
{
	srand((unsigned)time(0));
	for (int i = 0; i < pointsLength; i++)
	{
		points[i].x = rand() % 960;
		points[i].y = rand() % 540;
		for (int j = 0; j < i; j++)
		{
			if (points[j].x == points[i].x && points[j].y == points[j].x)
			{
				i--;
			}
		}
	}
	return;
}
//获得两点距离
int Distance(Point point1, Point point2)
{                                                                                                                                                                                                                                           
	int distance = sqrt(pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2));
	return distance;
}
//归并排序
void sort(Point points[], int s, int e,char z)
{
	if (s < e)
	{
		int mid = (s + e) / 2;
		sort(points, s, mid, z);
		sort(points, mid + 1, e, z);
		merge(points, s, e, mid, z);
		return;
	}
}
//归并
void merge(Point points[], int s, int e, int mid, char z)
{
	int length1 = mid - s + 1;
	int length2 = e - mid;
	Point  *AL = (Point*)malloc(sizeof(Point)*length1);
	Point *AR = (Point*)malloc(sizeof(Point)*length2);
	int i = 0, j = 0, k = s;
	for (i = s; i <= mid; i++)
	{
		AL[i - s] = points[i];
	}
	for (j = mid + 1; j <= e; j++)
	{
		AR[j - mid - 1] = points[j];
	}
	switch (z)
	{
	case 'x':
		i = 0; j = 0;
		while (i < length1&&j < length2)
		{
			if (AL[i].x < AR[j].x)
			{
				points[k++] = AL[i++];
			}
			else points[k++] = AR[j++];
		}
		while (i < length1)
		{
			points[k++] = AL[i++];
		}
		while (j < length2)
		{
			points[k++] = AR[j++];
		}
		break;
	case 'y':
		i = 0; j = 0;
		while (i < length1&&j < length2)
		{
			if (AL[i].y < AR[j].y)
			{
				points[k++] = AL[i++];
			}
			else points[k++] = AR[j++];
		}
		while (i < length1)
		{
			points[k++] = AL[i++];
		}
		while (j < length2)
		{
			points[k++] = AR[j++];
		}
		break;
	default:
		free(AL);
		free(AR);
		break;
	}
	return;
}
//按中心划分左右两部分点对
void divideByMid(int mid, Point points[], Point pointsL[], Point pointsR[], int n)
{
	int i = 0, j = 0, k = 0;
	for (i = 0; i < n; i++)
	{
		if (points[i].x > mid) 
		{
			pointsR[j++] = points[i];
		}
		else {
			pointsL[k++] = points[i];
		}
	}
	return;
}
//在左右点集中获得最近点对
int getClosestInSides(Point points[], int pointsLength)
{
	int distance;
	if (pointsLength < 2)
	{
		distance = MYINFINITE;
	}
	else if (pointsLength == 2)
	{
		distance = Distance(points[0], points[1]);
	}
	else
	{
		Point * pointsL = (Point*)malloc(sizeof(Point)*(pointsLength));
		Point * pointsR = (Point*)malloc(sizeof(Point)*(pointsLength));
		for (int i = 0; i < pointsLength; i++)
		{
			if (i < pointsLength / 2)
			{
				pointsL[i].x = 0;
				pointsL[i].y = 0;
			}
			else
			{
				pointsR[i - pointsLength / 2].x = 0;
				pointsR[i - pointsLength / 2].y = 0;
			}
		}
		sort(points, 0, pointsLength - 1, 'x');
		divideByMid(points[pointsLength/2].x, points, pointsL, pointsR,pointsLength);
		int distance_L = getClosestInSides(pointsL, pointsLength / 2);
		int distance_R = getClosestInSides(pointsR, pointsLength - pointsLength / 2);
		if (distance_L > distance_R)
		{
			distance = distance_L;
		}
		else distance = distance_R;
		free(pointsR);
		free(pointsL);
	}
	return distance;
}
//获取全局最近点对
int getClosest(Point points[], Point result[2], int pointsLength)
{
	int distance = getClosestInSides(points, pointsLength);
	sort(points, 0, pointsLength - 1, 'y');
	Point * pointsCenter = (Point *)malloc(sizeof(Point)*pointsLength);
	int pointsCenterLength = -1;
	for (int i = 0; i < pointsLength; i++)
	{
		if (fabs(points[i].x - points[pointsLength/2].x) < distance)
		{
			pointsCenter[++pointsCenterLength] = points[i];
		}
	}
	for (int i = 0; i < pointsCenterLength; i++)
	{
		for (int j = i + 1; j <= i + 7 && j < pointsCenterLength; j++)
		{
			if (Distance(pointsCenter[i], pointsCenter[j]) < distance)
			{
				distance = Distance(pointsCenter[i], pointsCenter[j]);
				result[0] = pointsCenter[i];
				result[1] = pointsCenter[j];
			}
		}
	}
	free(pointsCenter);
	return distance;
}

3.结果

结果