我试图在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是用于计算角度的基点。
它没有按正确的顺序排序,我无法看到问题。如果有人能够指出它,我将不胜感激。
答案 0 :(得分:0)
我认为使用epsilon的比较实现是不正确的。
众所周知,如果a == b
和b == c
,则a == c
。但是,此实施可能会导致a == b
,b == 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);