|
| 1 | +//Created by Ahmed Nader (github: AhmedNader42) on 4/4/18. |
| 2 | + |
| 3 | +func ClosestPairOf(points: [Point]) -> (minimum:Double, firstPoint:Point, secondPoint:Point) { |
| 4 | + var innerPoints = mergeSort(points, sortAccording : true) |
| 5 | + let result = ClosestPair(&innerPoints, innerPoints.count) |
| 6 | + return (result.minValue, result.firstPoint, result.secondPoint) |
| 7 | +} |
| 8 | + |
| 9 | +func ClosestPair(_ p : inout [Point],_ n : Int) -> (minValue: Double,firstPoint: Point,secondPoint: Point) |
| 10 | +{ |
| 11 | + // Brute force if only 3 points (To end recursion) |
| 12 | + if n <= 3 |
| 13 | + { |
| 14 | + var i=0, j = i+1 |
| 15 | + var minDist = Double.infinity |
| 16 | + var newFirst:Point? = nil |
| 17 | + var newSecond:Point? = nil |
| 18 | + while i<n |
| 19 | + { |
| 20 | + j = i+1 |
| 21 | + while j < n |
| 22 | + { |
| 23 | + if dist(p[i], p[j]) <= minDist |
| 24 | + { |
| 25 | + minDist = dist(p[i], p[j]) |
| 26 | + newFirst = p[i] |
| 27 | + newSecond = p[j] |
| 28 | + } |
| 29 | + j+=1 |
| 30 | + } |
| 31 | + i+=1 |
| 32 | + |
| 33 | + } |
| 34 | + return (minDist, newFirst ?? Point(0,0), newSecond ?? Point(0,0)) |
| 35 | + } |
| 36 | + |
| 37 | + |
| 38 | + |
| 39 | + let mid:Int = n/2 |
| 40 | + let line:Double = (p[mid].x + p[mid+1].x)/2 |
| 41 | + |
| 42 | + // Split the array. |
| 43 | + var leftSide = [Point]() |
| 44 | + var rightSide = [Point]() |
| 45 | + for s in 0..<mid |
| 46 | + { |
| 47 | + leftSide.append(p[s]) |
| 48 | + } |
| 49 | + for s in mid..<p.count |
| 50 | + { |
| 51 | + rightSide.append(p[s]) |
| 52 | + } |
| 53 | + |
| 54 | + |
| 55 | + // Recurse on the left and right part of the array. |
| 56 | + let valueFromLeft = ClosestPair(&leftSide, mid) |
| 57 | + let minLeft:Double = valueFromLeft.minValue |
| 58 | + let valueFromRight = ClosestPair(&rightSide, n-mid) |
| 59 | + let minRight:Double = valueFromRight.minValue |
| 60 | + |
| 61 | + // Starting current min must be the largest possible to not affect the real calculations. |
| 62 | + var min = Double.infinity |
| 63 | + |
| 64 | + var first:Point |
| 65 | + var second:Point |
| 66 | + |
| 67 | + // Get the minimum between the left and the right. |
| 68 | + if minLeft < minRight { |
| 69 | + min = minLeft |
| 70 | + first = valueFromLeft.firstPoint |
| 71 | + second = valueFromLeft.secondPoint |
| 72 | + } |
| 73 | + else { |
| 74 | + min = minRight |
| 75 | + first = valueFromRight.firstPoint |
| 76 | + second = valueFromRight.secondPoint |
| 77 | + } |
| 78 | + |
| 79 | + // Sort the array according to Y. |
| 80 | + p = mergeSort(p, sortAccording: false) |
| 81 | + |
| 82 | + |
| 83 | + var strip = [Point]() |
| 84 | + |
| 85 | + // If the value is less than the min distance away in X from the line then take it into consideration. |
| 86 | + var i=0, j = 0 |
| 87 | + while i<n |
| 88 | + { |
| 89 | + if abs(p[i].x - line) < min |
| 90 | + { |
| 91 | + strip.append(p[i]) |
| 92 | + j+=1 |
| 93 | + } |
| 94 | + i+=1 |
| 95 | + } |
| 96 | + |
| 97 | + |
| 98 | + i=0 |
| 99 | + var x = i+1 |
| 100 | + var temp = min |
| 101 | + var tempFirst:Point = Point(0,0) |
| 102 | + var tempSecond:Point = Point(0,0) |
| 103 | + // Get the values between the points in the strip but only if it is less min dist in Y. |
| 104 | + while i<j |
| 105 | + { |
| 106 | + x = i+1 |
| 107 | + while x < j |
| 108 | + { |
| 109 | + if (abs(strip[x].y - strip[i].y)) > min { break } |
| 110 | + if dist(strip[i], strip[x]) < temp |
| 111 | + { |
| 112 | + temp = dist(strip[i], strip[x]) |
| 113 | + tempFirst = strip[i] |
| 114 | + tempSecond = strip[x] |
| 115 | + } |
| 116 | + x+=1 |
| 117 | + } |
| 118 | + i+=1 |
| 119 | + } |
| 120 | + |
| 121 | + if temp < min |
| 122 | + { |
| 123 | + min = temp; |
| 124 | + first = tempFirst |
| 125 | + second = tempSecond |
| 126 | + } |
| 127 | + return (min, first, second) |
| 128 | +} |
| 129 | + |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | +// MergeSort the array (Taken from Swift Algorithms Club with |
| 134 | +// minor addition) |
| 135 | +// sortAccodrding : true -> x, false -> y. |
| 136 | +func mergeSort(_ array: [Point], sortAccording : Bool) -> [Point] { |
| 137 | + guard array.count > 1 else { return array } |
| 138 | + let middleIndex = array.count / 2 |
| 139 | + let leftArray = mergeSort(Array(array[0..<middleIndex]), sortAccording: sortAccording) |
| 140 | + let rightArray = mergeSort(Array(array[middleIndex..<array.count]), sortAccording: sortAccording) |
| 141 | + return merge(leftPile: leftArray, rightPile: rightArray, sortAccording: sortAccording) |
| 142 | +} |
| 143 | + |
| 144 | + |
| 145 | +private func merge(leftPile: [Point], rightPile: [Point], sortAccording: Bool) -> [Point] { |
| 146 | + |
| 147 | + var compare : (Point, Point) -> Bool |
| 148 | + |
| 149 | + // Choose to compare with X or Y. |
| 150 | + if sortAccording |
| 151 | + { |
| 152 | + compare = { p1,p2 in |
| 153 | + return p1.x < p2.x |
| 154 | + } |
| 155 | + } |
| 156 | + else |
| 157 | + { |
| 158 | + compare = { p1, p2 in |
| 159 | + return p1.y < p2.y |
| 160 | + } |
| 161 | + } |
| 162 | + |
| 163 | + var leftIndex = 0 |
| 164 | + var rightIndex = 0 |
| 165 | + var orderedPile = [Point]() |
| 166 | + if orderedPile.capacity < leftPile.count + rightPile.count { |
| 167 | + orderedPile.reserveCapacity(leftPile.count + rightPile.count) |
| 168 | + } |
| 169 | + |
| 170 | + while true { |
| 171 | + guard leftIndex < leftPile.endIndex else { |
| 172 | + orderedPile.append(contentsOf: rightPile[rightIndex..<rightPile.endIndex]) |
| 173 | + break |
| 174 | + } |
| 175 | + guard rightIndex < rightPile.endIndex else { |
| 176 | + orderedPile.append(contentsOf: leftPile[leftIndex..<leftPile.endIndex]) |
| 177 | + break |
| 178 | + } |
| 179 | + |
| 180 | + if compare(leftPile[leftIndex], rightPile[rightIndex]) { |
| 181 | + orderedPile.append(leftPile[leftIndex]) |
| 182 | + leftIndex += 1 |
| 183 | + } else { |
| 184 | + orderedPile.append(rightPile[rightIndex]) |
| 185 | + rightIndex += 1 |
| 186 | + } |
| 187 | + } |
| 188 | + return orderedPile |
| 189 | +} |
| 190 | + |
| 191 | + |
| 192 | +// Structure to represent a point. |
| 193 | +struct Point |
| 194 | +{ |
| 195 | + var x: Double |
| 196 | + var y: Double |
| 197 | + |
| 198 | + init(_ x:Double,_ y:Double) { |
| 199 | + self.x = x |
| 200 | + self.y = y |
| 201 | + } |
| 202 | +} |
| 203 | +// Get the distance between two points a, b. |
| 204 | +func dist(_ a: Point,_ b: Point) -> Double |
| 205 | +{ |
| 206 | + let equation:Double = (((a.x-b.x)*(a.x-b.x))) + (((a.y-b.y)*(a.y-b.y))) |
| 207 | + return equation.squareRoot() |
| 208 | +} |
| 209 | + |
| 210 | + |
| 211 | +var a = Point(0,2) |
| 212 | +var b = Point(6,67) |
| 213 | +var c = Point(43,71) |
| 214 | +var d = Point(1000,1000) |
| 215 | +var e = Point(39,107) |
| 216 | +var f = Point(2000,2000) |
| 217 | +var g = Point(3000,3000) |
| 218 | +var h = Point(4000,4000) |
| 219 | + |
| 220 | + |
| 221 | +var points = [a,b,c,d,e,f,g,h] |
| 222 | +let endResult = ClosestPairOf(points: points) |
| 223 | +print("Minimum Distance : \(endResult.minimum), The two points : (\(endResult.firstPoint.x ),\(endResult.firstPoint.y)), (\(endResult.secondPoint.x),\(endResult.secondPoint.y))") |
| 224 | + |
0 commit comments