def find_hull(self, points): # Get the length of the list of points num_points = len(points) # Base case # If there is only 1 point, make a node for that point, make a hull using that node, and return the hull if num_points == 1: node = Node(points[0], None, None) node.next_node = node node.previous_node = node hull = Hull(node, node) return hull # Otherwise, if there is more than 1 point, split the list of points in half and find hulls for the left half # and the right half. Once both hulls have been found, merge them # The time complexity is O(nlog(n)) because the points are split in half at each iteration, so there are log(n) # recursive calls, and merge_hulls is called at each recursive level, which runs in O(n) time. So the # complexity is O(n) * O(log(n)), or O(nlog(n)) # The space complexity is also O(nlog(n)), since there are log(n) recursive calls, and merge_hulls is called at # each recursive level, which has a space complexity of O(n). So the complexity is O(n) * O(log(n)), or # O(nlog(n)) else: mid = num_points // 2 left_hull = self.find_hull(points[:mid]) right_hull = self.find_hull(points[mid:]) hull = self.merge_hulls(left_hull, right_hull) return hull
def merge_hulls(self, left_hull, right_hull): # Find the upper and lower tangents (the tangents are tuples containing the 2 nodes the tangent goes through) upper_tangent = self.find_upper_tangent(left_hull.right_node, right_hull.left_node) lower_tangent = self.find_lower_tangent(left_hull.right_node, right_hull.left_node) # Set the upper tangent's left node's next node to the upper tangent's right node. Then set the upper tangent's # right node's previous node to the upper tangent's left node upper_tangent[0].next_node = upper_tangent[1] upper_tangent[1].previous_node = upper_tangent[0] # Set the lower tangent's right node's next node to the lower tangent's left node. Then set the lower tangent's # left node's previous node to the lower tangent's right node lower_tangent[1].next_node = lower_tangent[0] lower_tangent[0].previous_node = lower_tangent[1] # Once the proper node changes have been made, any other unimportant nodes will be garbage collected # We can now merge the hulls by creating a new hull that uses the left hull's left node and the right hull's # right node merged_hull = Hull(left_hull.left_node, right_hull.right_node) # Return the merged hull return merged_hull