在c#中按角度对点数组进行排序

时间:2016-09-24 15:21:26

标签: c# arrays sorting

我试图在C#中实现Graham算法来寻找凸包。它包括按点与基点的角度对点进行排序的步骤。我尝试使用从Comparer继承的类使用Array.Sort方法实现它。

这是班级

class ReversePolarSorter : Comparer<Point>
    {
        double e = 0.000001;
        double m_baseX;
        double m_baseY;
        public ReversePolarSorter(Point basePoint)
        {
            m_baseX = basePoint.X;
            m_baseY = basePoint.Y;
        }

        public override int Compare(Point a,  Point b)
        {


            double angleA = Math.Atan2(a.Y - m_baseY, a.X - m_baseX);
            double angleB= Math.Atan2(b.Y - m_baseY, b.X - m_baseX);
            int result;
            if (Math.Abs(angleA - angleB) < e)
                result= 0;
            else
                result= angleA.CompareTo(angleB);

            return result;
        }
    }

然后我用

来排序
Comparer<Point> sorter = new ReversePolarSorter(coords[m_pointsNumber-1]);
Array.Sort<Point>(coords, 0, m_pointsNumber - 2, sorter);

coords是一系列点。 m_pointsNumber是多个点 m_pointsNumber-1是用于计算角度的基点。

它没有按正确的顺序排序,我无法看到问题。如果有人能够指出它,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

我认为使用epsilon的比较实现是不正确的。

众所周知,如果a == bb == c,则a == c。但是,此实施可能会导致a == bb == c,但会a < c,这会破坏排序算法。

由于你有一个基点,你可以使用舍入而不是epsilon:

class ReversePolarSorter : Comparer<Point>
{
    const int precision = 6;
    double m_baseX;
    double m_baseY;
    public ReversePolarSorter(Point basePoint)
    {
        m_baseX = basePoint.X;
        m_baseY = basePoint.Y;
    }

    double GetAngle(Point p)
    {
        return Math.Round(Math.Atan2(p.Y - m_baseY, p.X - m_baseX), precision);
    }

    public override int Compare(Point a,  Point b)
    {
        return GetAngle(a).CompareTo(GetAngle(b));
    }
}

另请注意,Array.Sort的第三个参数是长度,因此如果m_pointsNumber是多个点并且指向索引m_pointsNumber - 1,则基点,然后您应该将m_pointsNumber - 1作为 length 传递:

Array.Sort(coords, 0, m_pointsNumber - 1, sorter);