在C#中实现Graham Scan

本文关键字:Graham Scan 实现 | 更新日期: 2023-09-27 18:28:06

我正试图从维基百科的伪代码中实现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;
        }


    }

代码喜欢爆炸,主要是因为我读过十几个完全不同的伪实现,没有一个能充分解释问题。我得到了一个数组的越界错误,我甚至不确定它应该是coordinatesize,或coordinatesize+1,或cooordinatesize+killme->最初是'N'或'N+1',但正如你所看到的,我正在慢慢忘记这个翻译。

在C#中实现Graham Scan

这个问题可能已经死了,但它出现在StackOverflow的"相关"问题中,因为我在这里添加了Graham扫描的c#实现:Graham在大量点处扫描问题。事实上,维基百科算法在点和起始最小点共线的情况下确实存在缺陷。