最近点对问题
找出平面上一对距离最短的点,时间复杂度 O(nlgn)
using System;
using System.Collections.Generic;
namespace dataLearn
{
struct Coordinate
{
public float x;
public float y;
public Coordinate(float x,float y)
{
this.x = x;
this.y = y;
}
public override string ToString()
{
return $"x:{x},y:{y}";
}
public void print()
{
Console.Out.WriteLine(this);
}
}
class Program
{
static void Main(string[] args)
{
List<Coordinate> coordinates = new List<Coordinate> { new Coordinate(1,2),new Coordinate(1,6),
new Coordinate(2,4),new Coordinate(2,8),new Coordinate(3,1),new Coordinate(3,6),new Coordinate(3,10),
new Coordinate(4,3),new Coordinate(5,1),new Coordinate(5,5),new Coordinate(5,9),new Coordinate(6,7),
new Coordinate(7,1),new Coordinate(7,4),new Coordinate(7,9),new Coordinate(8,6)};
coordinates.Sort((x, y) =>
{
if (x.x == y.x) return 0;
else if (x.x > y.x) return 1;
else return -1;
});
var co = getShortestDistance(coordinates, 0, coordinates.Count - 1);
co.Item1.print();
co.Item2.print();
Console.Out.Write(" distance "+co.d);
}
static float getDistance(Coordinate x, Coordinate y)
{
return (float)Math.Sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y));
}
static (Coordinate, Coordinate, float d) getShortestDistance(List<Coordinate> coordinates, int start, int end)
{
int length = end - start + 1;
if (length > 3)
{
int middle = (start + end) / 2;
var dl = getShortestDistance(coordinates, start, middle);
var dr = getShortestDistance(coordinates, middle + 1, end);
float d = Math.Min(dl.d, dr.d);
float left = coordinates[middle].x - d;
float right = coordinates[middle].x + d;
int child_start = 0;
int child_end = 0;
for (int i = start; i < end+1; i++)
{
if (child_start == 0 && coordinates[i].x >= left)
{
child_start = i;
}
else if (coordinates[i].x <= right)
{
child_end = i;
}
else
break;
}
List<Coordinate> temp = new List<Coordinate>();
for (int i = child_start; i <= child_end; i++)
{
temp.Add(coordinates[i]);
}
temp.Sort((x,y)=>
{
if (x.y == y.y) return 0;
else if (x.y > y.y) return 1;
else return -1;
});
float dmin = d;
int c1 = 0, c2 = 0;
for(int i= 0;i<temp.Count-1;i++)
{
for (int j=i+1;j<temp.Count;j++)
{
if (temp[i].y + d < temp[j].y)
{
break;
}
else if (getDistance(temp[i], temp[j]) < dmin)
{
dmin = getDistance(temp[i], temp[j]);
c1 = i;
c2 = j;
}
}
}
if (dmin < d)
{
return (temp[c1], temp[c2], dmin);
}
else return dl.d <= dr.d ? dl : dr;
}
else if (length == 3)
{
float d12 = getDistance(coordinates[start], coordinates[start + 1]);
float d23 = getDistance(coordinates[start + 1], coordinates[start + 2]);
float d13 = getDistance(coordinates[start], coordinates[start + 2]);
if (d12 <= d23 && d12 <= d13)
{
return (coordinates[start], coordinates[start + 1], d12);
}
else if (d23 <= d12 && d23 <= d13)
{
return (coordinates[start + 1], coordinates[start + 2], d23);
}
else
{
return (coordinates[start], coordinates[start + 2], d13);
}
}
else
{
return (coordinates[start], coordinates[end], getDistance(coordinates[start], coordinates[end]));
}
}
}
}