C# 如何将此分治代码转换为将一个点与一组点进行比较?

C# 如何将此分治代码转换为将一个点与一组点进行比较?,c#,algorithm,C#,Algorithm,我在网站上找到了这段代码,我采用了C#版本的分治法来寻找最近的一对点,但我正在尝试做的是修改它,以便只找到离一个特定点最近的点。我在谷歌上搜索了很多,并在这个网站上找到了一些例子,但没有一个像这样。我不完全确定要更改什么,因此它只检查列表中的一个点,而不是检查列表以找到最接近的两个点。我想让我的程序尽可能快地运行,因为它可以搜索几千个点的列表,以找到最接近我当前坐标点的点 public class Segment { public Segment(PointF p1, PointF p2

我在网站上找到了这段代码,我采用了C#版本的分治法来寻找最近的一对点,但我正在尝试做的是修改它,以便只找到离一个特定点最近的点。我在谷歌上搜索了很多,并在这个网站上找到了一些例子,但没有一个像这样。我不完全确定要更改什么,因此它只检查列表中的一个点,而不是检查列表以找到最接近的两个点。我想让我的程序尽可能快地运行,因为它可以搜索几千个点的列表,以找到最接近我当前坐标点的点

public class Segment
{
    public Segment(PointF p1, PointF p2)
    {
        P1 = p1;
        P2 = p2;
    }

    public readonly PointF P1;
    public readonly PointF P2;

    public float Length()
    {
        return (float)Math.Sqrt(LengthSquared());
    }

    public float LengthSquared()
    {
        return (P1.X - P2.X) * (P1.X - P2.X)
            + (P1.Y - P2.Y) * (P1.Y - P2.Y);
    }
}

    public static Segment Closest_BruteForce(List<PointF> points)
    {
        int n = points.Count;
        var result = Enumerable.Range(0, n - 1)
            .SelectMany(i => Enumerable.Range(i + 1, n - (i + 1))
                .Select(j => new Segment(points[i], points[j])))
                .OrderBy(seg => seg.LengthSquared())
                .First();

        return result;
    }

    public static Segment MyClosestDivide(List<PointF> points)
    {
        return MyClosestRec(points.OrderBy(p => p.X).ToList());
    }

    private static Segment MyClosestRec(List<PointF> pointsByX)
    {
        int count = pointsByX.Count;
        if (count <= 4)
            return Closest_BruteForce(pointsByX);

        // left and right lists sorted by X, as order retained from full list
        var leftByX = pointsByX.Take(count / 2).ToList();
        var leftResult = MyClosestRec(leftByX);

        var rightByX = pointsByX.Skip(count / 2).ToList();
        var rightResult = MyClosestRec(rightByX);

        var result = rightResult.Length() < leftResult.Length() ? rightResult : leftResult;

        // There may be a shorter distance that crosses the divider
        // Thus, extract all the points within result.Length either side
        var midX = leftByX.Last().X;
        var bandWidth = result.Length();
        var inBandByX = pointsByX.Where(p => Math.Abs(midX - p.X) <= bandWidth);

        // Sort by Y, so we can efficiently check for closer pairs
        var inBandByY = inBandByX.OrderBy(p => p.Y).ToArray();

        int iLast = inBandByY.Length - 1;
        for (int i = 0; i < iLast; i++)
        {
            var pLower = inBandByY[i];

            for (int j = i + 1; j <= iLast; j++)
            {
                var pUpper = inBandByY[j];

                // Comparing each point to successivly increasing Y values
                // Thus, can terminate as soon as deltaY is greater than best result
                if ((pUpper.Y - pLower.Y) >= result.Length())
                    break;

                Segment segment = new Segment(pLower, pUpper);
                if (segment.Length() < result.Length())
                    result = segment;// new Segment(pLower, pUpper);
            }
        }

        return result;
    }

根本不使用这种算法,只需逐个浏览列表,比较与参考点的距离,最后返回最接近的点。这将是O(n)

你可能会增加一些额外的加速,但这应该足够好了


如果您愿意,我可以编写一些示例代码。

完全不要使用此算法,只需逐个浏览列表,比较与参考点的距离,最后返回最接近的点。这将是O(n)

你可能会增加一些额外的加速,但这应该足够好了


如果你愿意,我可以写一些示例代码。

你把两个不同的问题混在一起了。最接近对问题的分而治之比暴力更快的唯一原因是它避免了将每个点与其他点进行比较,从而得到O(n logn)而不是O(n*n)。但是找到离一个点最近的点就是O(n)。当检查少于n个点时,如何在n个点的列表中找到最近的点?你想做的根本没有意义


我说不出为什么你们的分而治之的时间比你们的蛮力要短;也许linq实现运行得比较慢。但我认为你会发现两件事:1)即使从绝对意义上讲,你的分而治之1分的实施时间比你的暴力1分的实施时间要短,他们仍然有相同的O(n)。2) 如果你只是尝试一个简单的foreach循环并记录最小距离的平方,你会得到比分而治之更好的绝对时间-而且,它仍然是O(n)。

你混淆了两个不同的问题。最接近对问题的分而治之比暴力更快的唯一原因是它避免了将每个点与其他点进行比较,从而得到O(n logn)而不是O(n*n)。但是找到离一个点最近的点就是O(n)。当检查少于n个点时,如何在n个点的列表中找到最近的点?你想做的根本没有意义


我说不出为什么你们的分而治之的时间比你们的蛮力要短;也许linq实现运行得比较慢。但我认为你会发现两件事:1)即使从绝对意义上讲,你的分而治之1分的实施时间比你的暴力1分的实施时间要短,他们仍然有相同的O(n)。2) 如果您只需尝试一个简单的foreach循环并记录最小距离平方,您将获得比分治更好的绝对时间-而且,它仍然是O(n)。

您可以将点存储在更好的数据结构中,利用它们的位置。有点像一辆汽车


您尝试使用的分治算法实际上不适用于此问题。

您可以将点存储在更好的数据结构中,以利用其位置。有点像一辆汽车

public static float LengthSquared(PointF P1, PointF P2)
{
    return (P1.X - P2.X) * (P1.X - P2.X)
        + (P1.Y - P2.Y) * (P1.Y - P2.Y);
}
您尝试使用的分治算法实际上不适用于此问题

public static float LengthSquared(PointF P1, PointF P2)
{
    return (P1.X - P2.X) * (P1.X - P2.X)
        + (P1.Y - P2.Y) * (P1.Y - P2.Y);
}
如问题所述,如果要将1个(已知)点与点列表进行比较,以找到最接近的点,请使用此代码

public static Segment Closest_BruteForce(PointF P1, List<PointF> points)
{
    PointF closest = null;
    float minDist = float.MaxValue;
    foreach(PointF P2 in points) 
    {
       if(P1 != P2) 
       {
           float temp = LengthSquared(P1, P2);
           if(temp < minDist) 
           {
               minDist = temp;
               closest = P2;
           }
       }
    }
    return new Segment(P1, closest);
}
公共静态段最近的\u BruteForce(点F P1,列表点)
{
最接近的点f=null;
float minDist=float.MaxValue;
foreach(点F P2以点为单位)
{
如果(P1!=P2)
{
浮子温度=长度平方(P1,P2);
如果(临时
但是,如果如您的示例所示,您希望从点列表中找到最近的2个点,请尝试以下方法

public static Segment Closest_BruteForce(List<PointF> points)
{
    PointF closest1;
    PointF closest2;
    float minDist = float.MaxValue;
    for(int x=0; x<points.Count; x++)
    {
        PointF P1 = points[x];
        for(int y = x + 1; y<points.Count; y++)
        {
            PointF P2 = points[y];
            float temp = LengthSquared(P1, P2);
            if(temp < minDist) 
            {
               minDist = temp;
               closest1 = P1;
               closest2 = P2;
            }
        }
    }
    return new Segment(closest1, closest2);
}
公共静态段最近的\u BruteForce(列表点)
{
点F关闭1;
点F关闭2;
float minDist=float.MaxValue;
对于(int x=0;x
如问题所述,如果要将1个(已知)点与点列表进行比较,以找到最接近的点,请使用此代码

public static Segment Closest_BruteForce(PointF P1, List<PointF> points)
{
    PointF closest = null;
    float minDist = float.MaxValue;
    foreach(PointF P2 in points) 
    {
       if(P1 != P2) 
       {
           float temp = LengthSquared(P1, P2);
           if(temp < minDist) 
           {
               minDist = temp;
               closest = P2;
           }
       }
    }
    return new Segment(P1, closest);
}
公共静态段最近的\u BruteForce(点F P1,列表点)
{
最接近的点f=null;
float minDist=float.MaxValue;
foreach(点F P2以点为单位)
{
如果(P1!=P2)
{
浮子温度=长度平方(P1,P2);
如果(临时
但是,如果如您的示例所示,您希望从点列表中找到最近的2个点,请尝试以下方法

public static Segment Closest_BruteForce(List<PointF> points)
{
    PointF closest1;
    PointF closest2;
    float minDist = float.MaxValue;
    for(int x=0; x<points.Count; x++)
    {
        PointF P1 = points[x];
        for(int y = x + 1; y<points.Count; y++)
        {
            PointF P2 = points[y];
            float temp = LengthSquared(P1, P2);
            if(temp < minDist) 
            {
               minDist = temp;
               closest1 = P1;
               closest2 = P2;
            }
        }
    }
    return new Segment(closest1, closest2);
}
公共静态段最近的\u BruteForce(列表点)
{
点F关闭1;
点F关闭2;
float minDist=float.MaxValue;

对于(int x=0;x+1,用于说明他要求的是更好的算法,但他需要的是更好的数据结构。你能解释一下在这种情况下这将如何应用吗?除非你从树开始,否则我看不出组装它将如何加快速度。好吧。这取决于他需要什么。如果他只需要一轮计算当然,线性搜索是最优的。然而,如果他最终在多次迭代中测试多个点,那么