|
1 | 1 | """
|
2 |
| -The algorithm finds distance between closest pair of points in the given n points. |
3 |
| -Approach: Divide and conquer |
4 |
| -The points are sorted based on x-cords |
| 2 | +The algorithm finds distance btw closest pair of points in the given n points. |
| 3 | +Approach used -> Divide and conquer |
| 4 | +The points are sorted based on Xco-ords |
5 | 5 | & by applying divide and conquer approach,
|
6 | 6 | minimum distance is obtained recursively.
|
7 | 7 |
|
8 |
| -Edge case: closest points lie on different sides of partition |
| 8 | +>> closest points lie on different sides of partition |
9 | 9 | This case handled by forming a strip of points
|
10 |
| -which are at a distance (< closest_pair_dis) from mid-point. |
11 |
| -(It is a proven that strip contains at most 6 points) |
12 |
| -And brute force method is applied on strip to find closest points. |
| 10 | +whose Xco-ords distance is less than closest_pair_dis |
| 11 | +from mid-point's Xco-ords. |
| 12 | +Closest pair distance is found in the strip of points. (closest_in_strip) |
13 | 13 |
|
14 |
| -Time complexity: O(n * (logn) ^ 2) |
| 14 | +min(closest_pair_dis, closest_in_strip) would be the final answer. |
| 15 | + |
| 16 | +Time complexity: O(n * (logn)^2) |
15 | 17 | """
|
16 | 18 |
|
17 | 19 |
|
18 | 20 | import math
|
19 | 21 |
|
20 | 22 |
|
21 |
| -def euclidean_distance(point1, point2): |
22 |
| - return math.sqrt(pow(point1[0] - point2[0], 2) + pow(point1[1] - point2[1], 2)) |
| 23 | +def euclidean_distance_sqr(point1, point2): |
| 24 | + return pow(point1[0] - point2[0], 2) + pow(point1[1] - point2[1], 2) |
23 | 25 |
|
24 | 26 |
|
25 | 27 | def column_based_sort(array, column = 0):
|
26 | 28 | return sorted(array, key = lambda x: x[column])
|
27 | 29 |
|
28 | 30 |
|
29 |
| -#brute force approach to find distance between closest pair points |
30 |
| -def dis_btw_closest_pair(points, no_of_points, min_dis = float("inf")): |
31 |
| - for i in range(no_of_points - 1): |
32 |
| - for j in range(i+1, no_of_points): |
33 |
| - current_dis = euclidean_distance(points[i], points[j]) |
| 31 | +def dis_btw_closest_pair(points, points_counts, min_dis = float("inf")): |
| 32 | + """ brute force approach to find distance between closest pair points |
| 33 | +
|
| 34 | + Parameters : |
| 35 | + points, points_count, min_dis (tuple(tuple(int, int)), int, int) |
| 36 | + |
| 37 | + Returns : |
| 38 | + min_dis (float): distance between closest pair of points |
| 39 | +
|
| 40 | + """ |
| 41 | + |
| 42 | + for i in range(points_counts - 1): |
| 43 | + for j in range(i+1, points_counts): |
| 44 | + current_dis = euclidean_distance_sqr(points[i], points[j]) |
34 | 45 | if current_dis < min_dis:
|
35 | 46 | min_dis = current_dis
|
36 | 47 | return min_dis
|
37 | 48 |
|
38 | 49 |
|
39 |
| -#divide and conquer approach |
40 |
| -def closest_pair_of_points(points, no_of_points): |
| 50 | +def dis_btw_closest_in_strip(points, points_counts, min_dis = float("inf")): |
| 51 | + """ closest pair of points in strip |
| 52 | +
|
| 53 | + Parameters : |
| 54 | + points, points_count, min_dis (tuple(tuple(int, int)), int, int) |
| 55 | + |
| 56 | + Returns : |
| 57 | + min_dis (float): distance btw closest pair of points in the strip (< min_dis) |
| 58 | +
|
| 59 | + """ |
| 60 | + |
| 61 | + for i in range(min(6, points_counts - 1), points_counts): |
| 62 | + for j in range(max(0, i-6), i): |
| 63 | + current_dis = euclidean_distance_sqr(points[i], points[j]) |
| 64 | + if current_dis < min_dis: |
| 65 | + min_dis = current_dis |
| 66 | + return min_dis |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | +def closest_pair_of_points_sqr(points, points_counts): |
| 71 | + """ divide and conquer approach |
| 72 | +
|
| 73 | + Parameters : |
| 74 | + points, points_count (tuple(tuple(int, int)), int) |
| 75 | + |
| 76 | + Returns : |
| 77 | + (float): distance btw closest pair of points |
| 78 | +
|
| 79 | + """ |
| 80 | + |
41 | 81 | # base case
|
42 |
| - if no_of_points <= 3: |
43 |
| - return dis_btw_closest_pair(points, no_of_points) |
| 82 | + if points_counts <= 3: |
| 83 | + return dis_btw_closest_pair(points, points_counts) |
44 | 84 |
|
45 |
| - #recursion |
46 |
| - mid = no_of_points//2 |
| 85 | + # recursion |
| 86 | + mid = points_counts//2 |
47 | 87 | closest_in_left = closest_pair_of_points(points[:mid], mid)
|
48 |
| - closest_in_right = closest_pair_of_points(points[mid:], no_of_points - mid) |
| 88 | + closest_in_right = closest_pair_of_points(points[mid:], points_counts - mid) |
49 | 89 | closest_pair_dis = min(closest_in_left, closest_in_right)
|
50 | 90 |
|
51 |
| - #points which are at a distance (< closest_pair_dis) from mid-point |
| 91 | + """ cross_strip contains the points, whose Xcoords are at a |
| 92 | + distance(< closest_pair_dis) from mid's Xcoord |
| 93 | + """ |
| 94 | + |
52 | 95 | cross_strip = []
|
53 | 96 | for point in points:
|
54 | 97 | if abs(point[0] - points[mid][0]) < closest_pair_dis:
|
55 | 98 | cross_strip.append(point)
|
56 | 99 |
|
57 | 100 | cross_strip = column_based_sort(cross_strip, 1)
|
58 |
| - closest_in_strip = dis_btw_closest_pair(cross_strip, |
| 101 | + closest_in_strip = dis_btw_closest_in_strip(cross_strip, |
59 | 102 | len(cross_strip), closest_pair_dis)
|
60 | 103 | return min(closest_pair_dis, closest_in_strip)
|
| 104 | + |
61 | 105 |
|
| 106 | +def closest_pair_of_points(points, points_counts): |
| 107 | + return math.sqrt(closest_pair_of_points_sqr(points, points_counts)) |
| 108 | + |
62 | 109 |
|
63 |
| -points = [[2, 3], [12, 30], [40, 50], [5, 1], [12, 10]] |
| 110 | +points = ((2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (0, 2), (5, 6), (1, 2)) |
64 | 111 | points = column_based_sort(points)
|
65 | 112 | print("Distance:", closest_pair_of_points(points, len(points)))
|
66 | 113 |
|
|
0 commit comments