C# 实现动态比较的IComparable

C# 实现动态比较的IComparable,c#,.net,icomparable,C#,.net,Icomparable,根据当前的鼠标位置,我必须从列表中获得一个圆圈 这是圆形班 public class Circle { public Point Center; public Circle(int x, int y) { this.Center = new Point(x, y); } public int Distance(int x, i

根据当前的
鼠标位置,我必须从
列表中获得一个
圆圈

这是圆形班

public class Circle
        {
            public Point Center;

            public Circle(int x, int y)
            {
                this.Center = new Point(x, y);

            }
            public int Distance(int x, int y)
            {
                int result = 0;
                double part1 = Math.Pow((this.Center.X - x), 2);
                double part2 = Math.Pow((this.Center.Y - y), 2);
                double underRadical = part1 + part2;
                result = (int)Math.Sqrt(underRadical);
                return result;
            }
            public void Draw(Graphics g, Pen pen, int d)
            {
                g.DrawEllipse(pen, this.Center.X - d / 2, this.Center.Y - d/ 2, d, d );
            }
    }
下面是我如何从列表中检索圆的

public class UserControl1 : UserControl
{
private Circle currentCircle;
private List<Circle> circles = new List<Circle>();
private const int RADIUS = 16;
// ...snip
private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            currentCircle= this.circles 
                .Where(c => c.Distance(e.X, e.Y) < RADIUS )
                .DefaultIfEmpty(null)
                .First();
        }
//...snip
}
公共类UserControl1:UserControl
{
私人圈子;
私有列表圆圈=新列表();
私有常数int半径=16;
//…剪断
私有void Form1\u MouseMove(对象发送方,MouseEventArgs e)
{
currentCircle=this.circles
其中(c=>c.距离(e.X,e.Y)<半径)
.DefaultIfEmpty(null)
.First();
}
//…剪断
}

这对于小列表很好,但随着列表的增长,这会变得越来越慢。我想我可以使用List.BinarySearch来获得更好的性能,但我不知道如何在这种情况下实现
IComparable

尝试使用
HashSet
而不是
List
。随着数据量的增长,它需要有更好的性能-

二进制搜索只能在排序列表上工作。因此,您的
圆圈
对象需要具有可比性,以便获得排序列表。不过,我担心,您无法将它们按合理的线性顺序排列,以便更快地找到鼠标光标位置的“碰撞”


您可以在LINQ查询中使用
aspallel
,使用所有CPU核心进行比较。这仍然是
O(n)
,因此不能很好地缩放,但它可能会加快速度(考虑到
圆圈
对象的数量几乎没有增加)。

我会将比较移到圆圈,以便您可以做一些捷径。用更快的数学。我假设这些圆没有重叠。最坏情况(最多)4个框将包括该点,因此复杂方程最多计算4次

public bool Distance(double x, double y, double radius)
{
    double deltaX = this.Center.X - x;
    if (deltaX > radius) return false;   // test to see if this makes it faster
    double deltaY = this.Center.Y - y;
    if (deltaY > radius) return false;
    if ( (deltaX + deltaY) > radius) return false;   
    return ( (deltaX*deltaX + deltaY*deltaY) <= radius*radius) );
}
公共边界距离(双x、双y、双半径)
{
double deltaX=this.Center.X-X;
if(deltaX>radius)返回false;//测试这是否会加快速度
双deltaY=此.Center.Y-Y;
if(deltaY>radius)返回false;
如果((deltaX+deltaY)>半径)返回false;

返回((deltaX*deltaX+deltaY*deltaY)一个观察值-您可以取消
Math.Pow
Math.Sqrt
以节省时间。计算的距离变为“距离平方”,但由于所有圆都经历相同的缩放,因此这并不重要

但是,您需要一个解决方案,其中搜索的项目数量不会对查找匹配项所需的时间产生直接影响

因此,我认为您可能想看看KD树,它可以为大量维度数据提供快速性能。我从源代码中改编了一个完整的通用KD树;但是它似乎更好、更通用。不幸的是,我无法提供我的代码-它归我的雇主所有;)

在KD树中获得数据后,只需查找距离当前X,Y最近的圆(这是对KD树的一次调用),然后检查指针是否在该圆内,如果这是您要查找的

该结构实际上是一个二叉树,每一级的左/右值在连续维度上高于/低于“拆分平面”,环绕直到没有子节点。由于数据的存储方式,邻近搜索速度很快,因为当找到一个近邻时,只有同一拆分平面周围的其他邻居ng平面可以更接近(比这更微妙一点,实际上是一门比我能力更高的数学课)。因此,该算法很少需要检查所有节点以找到最接近的匹配项。不过,也就是说,在某些情况下,可能需要搜索所有节点;这与插入数据的顺序一样重要

因此,非常多的圆可能需要“平衡插入”(在中有一个很好的描述)。我链接的代码似乎做了某种形式的平衡插入,假设你有一个点列表来构建它-所以看起来你会没事的

此外,它在测量距离时的默认行为似乎是欧几里德距离,这正是您想要的


作为绩效的粗略概念(始终是一种主观衡量)我修改的KD树(我目前在其中插入了地图上点的哈弗斯距离计算)大约需要250-350毫秒来定位250000个点中最近的lat/long。欧几里德距离计算可能要快很多。

为鼠标输入注册一个事件处理程序如何?测试了这一点,在112 X 116处没有延迟。

    public MainWindow()
    {

        InitializeComponent();

        for (int j = 0; j < 112; j++)
        {
            for (int i = 0; i < 116; i++)
            {
                ellipse = new Ellipse();
                ellipse.Name = "EllipseX" + i.ToString() + "Y" + j.ToString();
                ellipse.StrokeThickness = 1;
                ellipse.Stroke = System.Windows.Media.Brushes.Blue;
                ellipse.Width = 5;
                ellipse.Height = 5;
                ellipse.MouseEnter += ellipse_MouseEnter;
                ellipse.MouseLeave += ellipse_MouseLeave;

                Canvas.SetTop(ellipse, 5 * j);
                Canvas.SetLeft(ellipse, 5 * i);
                Canvas1.Children.Add(ellipse);
            }
        }
    }

    private void ellipse_MouseEnter(object sender, MouseEventArgs e)
    {
        Ellipse ellipse = (Ellipse)sender;
        ellipse.Fill = System.Windows.Media.Brushes.Red;
        tbEname.Text = ellipse.Name;
    }

    private void ellipse_MouseLeave(object sender, MouseEventArgs e)
    {
        ((Ellipse)sender).Fill = System.Windows.Media.Brushes.Blue;
        tbEname.Text = string.Empty;
    }
public主窗口()
{
初始化组件();
对于(int j=0;j<112;j++)
{
对于(int i=0;i<116;i++)
{
椭圆=新椭圆();
椭圆.Name=“EllipseX”+i.ToString()+“Y”+j.ToString();
椭圆.StrokeThickness=1;
椭圆.Stroke=System.Windows.Media.Brushes.Blue;
椭圆,宽度=5;
椭圆,高度=5;
ellipse.MouseEnter+=椭圆\u MouseEnter;
ellipse.MouseLeave+=ellipse_MouseLeave;
帆布。机顶盒(椭圆,5*j);
Canvas.SetLeft(椭圆,5*i);
画布1.儿童。添加(椭圆);
}
}
}
专用无效椭圆\u鼠标指针(对象发送器,鼠标指针e)
{
椭圆=(椭圆)发送器;
椭圆.Fill=System.Windows.Media.Brushes.Red;
tbEname.Text=ellipse.Name;
}
私有无效椭圆\鼠标移动(对象发送器,鼠标移动目标)
{
((椭圆)sender).Fill=System.Windows.Media.brusks.Blue;
tbEname.Text=string.Empty;
}

是的,我已经试过了,性能,至少对我来说是这样