public static void TestClosestPairOfPoints() { Point[] allPoints = new Point[] { new Point(2, 3), new Point(12, 30), new Point(40, 50), new Point(5, 1), new Point(12, 10), new Point(3, 4) }; ClosestPairOfPoints cp = new ClosestPairOfPoints(); PairOfPoints pair = cp.GetTheClosestPoint(allPoints); Console.WriteLine("The closest pair of points are {0} and {1} and the minDistance is {2}", pair.PointA.ToString(), pair.PointB.ToString(), pair.Distance); }
/// <summary> /// this the merge subroutine of the divide and conquer approach /// </summary> /// <param name="pointsInStrip">this is the points present in the strip. These points are sorted wrt y axis</param> /// <param name="min">the current pair of points with minimum distance</param> /// <returns>pair of points with minimum distance after merging the 2 space</returns> private PairOfPoints Combine(List <Point> pointsInStrip, PairOfPoints min) { // Note this operations should take O(n) running time // it can be geometrically proven that each point in the strip needs to be compared with atmost 6 other points for (int i = 0; i < pointsInStrip.Count; i++) { for (int j = i + 1; j < pointsInStrip.Count; j++) { if (pointsInStrip[j].Ycoordinate - pointsInStrip[i].Ycoordinate > min.Distance) { // there is no point in checking more than j cause the distance will always ne greater than min.Distance break; } PairOfPoints currentPair = new PairOfPoints(pointsInStrip[i], pointsInStrip[j]); if (currentPair.Distance < min.Distance) { min = currentPair; } } } return(min); }
/// <summary> /// This is the divide subroutine in divide and conquer approach /// Here we divide the space into left and right and get the pair of points with minimum distance /// and then call the combine subroutine and return the pair of points with minimum distance /// </summary> /// <param name="ptsSortedByX">points sorted wrt x axis</param> /// <param name="ptsSortedByY">points sorted wrt y axis</param> /// <returns>pair of points with minimum distance</returns> private PairOfPoints GetClosestPointsSubroutine(Point[] ptsSortedByX, Point[] ptsSortedByY) { //Base case if (ptsSortedByX.Length < 2) { return(new PairOfPoints()); } else if (ptsSortedByX.Length == 2) { return(new PairOfPoints(ptsSortedByX[0], ptsSortedByX[1])); } int midIndex = ptsSortedByX.Length / 2; Point[] pointsOnLeftSideSortedByY = new Point[midIndex]; Point[] pointsOnRightSideSortedByY = new Point[ptsSortedByX.Length - (midIndex)]; // Element at the midIndex will lie on the right side Point[] pointsOnLeftSideSortedByX = new Point[midIndex]; Point[] pointsOnRightSideSortedByX = new Point[ptsSortedByX.Length - (midIndex)]; // Element at the midIndex will lie on the right side int leftIndex = 0; int rightIndex = 0; // Divide the ptsSortedByY into left and right of the line perpendicular to the x-axis and passing from the midIndex for (int i = 0; i < ptsSortedByY.Length; i++) { if (ptsSortedByY[i].Xcoordinate <= ptsSortedByX[midIndex].Xcoordinate && leftIndex < midIndex) { // this condition is used in case where there are duplicate Points with same Xcoordinates // and one point is the one in midIndex pointsOnLeftSideSortedByY[leftIndex++] = ptsSortedByY[i]; } else { pointsOnRightSideSortedByY[rightIndex++] = ptsSortedByY[i]; } if (i < midIndex) { pointsOnLeftSideSortedByX[i] = ptsSortedByX[i]; } else { pointsOnRightSideSortedByX[i - midIndex] = ptsSortedByX[i]; } } // Now solve the subproblem PairOfPoints leftMinPair = GetClosestPointsSubroutine(pointsOnLeftSideSortedByX, pointsOnLeftSideSortedByY); PairOfPoints rightMinPair = GetClosestPointsSubroutine(pointsOnRightSideSortedByX, pointsOnRightSideSortedByY); //get the min PairOfPoints min = leftMinPair; if (min.Distance > rightMinPair.Distance) { min = rightMinPair; } //Create the list with all the points in the strip List <Point> pointsInStrip = new List <Point>(); for (int i = 0; i < ptsSortedByY.Length; i++) { if (Math.Abs(ptsSortedByX[midIndex].Xcoordinate - ptsSortedByY[i].Xcoordinate) <= min.Distance) { pointsInStrip.Add(ptsSortedByY[i]); } } //Combine the left and right return(Combine(pointsInStrip, min)); }