在C#中实现Graham扫描

时间:2013-08-16 15:59:06

标签: c# grahams-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 - &gt;原来它是'N'或'N + 1',但正如你所看到的,我正慢慢失去了对这种翻译的看法。

1 个答案:

答案 0 :(得分:0)

这个问题可能已经死了,但它出现在StackOverflow&#34;相关&#34;问题,因为我在这里添加了格雷厄姆扫描的c#实现:Graham scan issue at high amount of points。实际上,维基百科算法在点彼此共线和起始最小点的情况下确实存在错误。