在 C# 中实现格雷厄姆扫描
Posted
技术标签:
【中文标题】在 C# 中实现格雷厄姆扫描【英文标题】:Implementing Graham Scan in C# 【发布时间】:2013-08-16 15:59:05 【问题描述】:我正在尝试从 Wikipedia 伪代码实现 Graham Scan,但在将内容转换为 C# 时遇到了一些麻烦。也许你不介意看看?
这是我所拥有的:
public class GrahamScan
public static List<CoordinatesD> Scan(List<CoordinatesD> coordinateslist)
int coordinatesize = coordinateslist.Count;
CoordinatesD[] coordinatesarray = new CoordinatesD[coordinatesize];
for (int i = 0; i < coordinatesize; i++)
coordinatesarray[i] = coordinateslist[i];
//swap points[1] with the point with the lowest y-coordinate;
int lowestyindex = LowestY(coordinatesarray);
Swap(coordinatesarray[0], coordinatesarray[lowestyindex]);
//sort points by polar angle with points[1];
coordinatesarray = SortByPolarAngle(coordinatesarray[0], coordinateslist);
// We want points[0] to be a sentinel point that will stop the loop.
coordinatesarray[0] = coordinatesarray[coordinatesize];
// M will denote the number of points on the convex hull.
int numpointsonhull = 1;
for (int i = 2; i < coordinatesize; i++)
// Find next valid point on convex hull.
while(CCW(coordinatesarray[numpointsonhull-1], coordinatesarray[numpointsonhull], coordinatesarray[i]) <= 0)
if(numpointsonhull > 1)
numpointsonhull -= 1;
// All points are collinear
else if (i == coordinatesize)
break;
else
i += 1;
// Update M and swap points[i] to the correct place.
numpointsonhull += 1;
//swap(points[M],points[i]);
Swap(coordinatesarray[numpointsonhull], coordinatesarray[i]);
List<CoordinatesD> pointsonhulllist = new List<CoordinatesD>();
for (int i = 0; i < numpointsonhull; i++)
pointsonhulllist.Add(coordinatesarray[i]);
return pointsonhulllist;
/// <summary>
/// Swaps two points.
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
private static void Swap(CoordinatesD p1, CoordinatesD p2)
CoordinatesD temp = p1;
p1 = p2;
p2 = temp;
/// <summary>
/// Attempts to Sort by Polar Angle, with respect to p1.
/// </summary>
/// <param name="p1"></param>
/// <param name="points"></param>
/// <returns></returns>
private static CoordinatesD[] SortByPolarAngle(CoordinatesD p1, List<CoordinatesD> points)
CoordinatesD[] sortedpoints = new CoordinatesD[points.Count];
int sortedpointiterator = 0;
while(true)
int current = 0;
for (int i = 0; i < points.Count; i++)
if (p1.PolarAngle - points[i].PolarAngle < p1.PolarAngle - points[current].PolarAngle)
current = i;
sortedpoints[sortedpointiterator] = points[current];
sortedpointiterator++;
points.RemoveAt(current);
if (points.Count == 0)
break;
return sortedpoints;
/// <summary>
/// Finds the index of the CoordinateD with the lowest Y.
/// </summary>
/// <param name="coords"></param>
/// <returns></returns>
private static int LowestY(CoordinatesD[] coords)
int index = 0;
for (int i = 0; i < coords.Length; i++)
if(coords[i].Y < coords[index].Y)
index = i;
return index;
// Three points are a counter-clockwise turn if ccw > 0, clockwise if
// ccw < 0, and collinear if ccw = 0 because ccw is a determinant that
// gives the signed area of the triangle formed by p1, p2 and p3.
private static double CCW(CoordinatesD p1, CoordinatesD p2, CoordinatesD p3)
return (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
它正在使用这个类:
public class CoordinatesD : iCoordinates
private double latitude = 0.0;
private double longitude = 0.0;
public enum ServiceType Google = 0, Bing = 1 ;
public double Latitude
get return latitude;
public double Longitude
get return longitude;
public double X
get return longitude;
public double Y
get return latitude;
public double PolarAngle get return CalculatePolarAngle();
public CoordinatesD(double latitude, double longitude)
this.latitude = latitude;
this.longitude = longitude;
private double CalculatePolarAngle()
double polarangle = Math.Atan(latitude / longitude);
if (polarangle > 0.0)
return polarangle;
return polarangle + Math.PI;
public CoordinatesD Change(double changelat, double changelong)
CoordinatesD newCoordinates = new CoordinatesD(this.latitude + changelat, this.longitude + changelong);
return newCoordinates;
public string ToJScriptString(ServiceType service)
string jscriptstring = string.Empty;
switch (service)
case ServiceType.Bing:
jscriptstring = String.Format("new Microsoft.Maps.Location(0,1)", this.latitude.ToString(), this.longitude.ToString());
break;
case ServiceType.Google:
jscriptstring = String.Format("new google.maps.LatLng(0,1)", this.latitude.ToString(), this.longitude.ToString());
break;
default:
break;
return jscriptstring;
代码喜欢爆炸,主要是因为我读过十几个完全不同的伪实现,没有一个能充分解释事情。我遇到了数组的越界错误,我什至不确定应该是坐标,还是坐标 + 1,还是坐标 - 1,或者坐标 + killme -> 最初是“N”或“N” +1',但正如你所看到的,我正在慢慢失去对这个翻译的想法。
【问题讨论】:
你能告诉我它在哪里爆炸吗? 你试过this吗? 目前它在 'coordinatesarray[0] = coordinatesarray[coordinatesize];' 上爆炸与索引超出范围异常一致(它应该这样做,因为它显然是在访问数组之外的东西)。我遇到的部分问题是翻译这段代码:“让 N = 点数”和“让点 [N+1] = 点数组”......就像他们使用从 0 开始然后使用 1有时基于索引。 【参考方案1】:这个问题很可能已经死了,但是它出现在 *** 的“相关”问题中,因为我在这里添加了 Graham 扫描的 c# 实现:Graham scan issue at high amount of points。 Wikipedia 算法在点和起始最小点共线的情况下确实存在错误。
【讨论】:
以上是关于在 C# 中实现格雷厄姆扫描的主要内容,如果未能解决你的问题,请参考以下文章
如何在 IBM Worklight 上的多个平台中实现条码扫描器?