def delete_at_beginning(self): if self.head is None: raise EmptyListError("List is empty, can't delete.") temp = self.head self.head = temp.get_next() temp.set_next(None)
def insert_at_position(self, position, data): """ Position is 1 based. """ if self.head is None: raise EmptyListError("List is empty, can't insert.") list_length = self.get_length() if not (1 <= position <= list_length + 1): raise RangeError( "Position range must be 1 through {0}.".format(list_length + 1)) if position == 1: self.insert_at_beginning(data) elif position == list_length + 1: self.insert_at_end(data) else: pointer = self.head pos = 1 while pos != position - 1: pointer = pointer.get_next() pos += 1 node = NodeCircular(data) node.set_next(pointer.get_next()) pointer.set_next(node)
def find_middle_of_the_list(linked_list): """ Find the middle node of a single linked list. :param SingleLinkedList linked_list: The linked list to operate. :return: data for middle node of the list. :rtype: int :raises EmptyListError: if the list is empty. """ if linked_list.head is None: raise EmptyListError("List is empty, cannot find middle") pointer1 = linked_list.head pointer2 = linked_list.head count = 0 # Move one pointer at one step, second pointer at two steps. # The pointer which traversed at one step a time would point to # middle node at the end of the iteration. while pointer1.get_next(): if count == 0: pointer1 = pointer1.get_next() count = 1 elif count == 1: pointer1 = pointer1.get_next() pointer2 = pointer2.get_next() count = 0 return pointer2.data
def nth_node_from_end(linked_list, n): """ Find nth node from end of a linked list (assume positions as 1 based). Hint: For a linked list of size m, nth node from end would be (m - n + 1)th node from beginning. :param SingleLinkedList linked_list: The linked list to operate. :param int n: The position from end. :return: the data of the node. :rtype: int :raises EmptyListError: if the list is empty. :raises RangeError: if length of list < n < 0. """ list_length = linked_list.get_length() if list_length == 0: raise EmptyListError("List is empty, can't find node") if not (1 <= n <= list_length): raise RangeError("Position range must be 1 through {0}".format(list_length)) nth_from_end = list_length - n + 1 pointer = linked_list.head position = 1 while position != nth_from_end: pointer = pointer.get_next() position += 1 return pointer.data
def insert_into_sorted_list(linked_list, data): """ Insert a node in a sorted linked list at its proper position. :param SingleLinkedList linked_list: The linked list to operate. :return: nothing. :rtype: None :raises EmptyListError: if the list is empty. """ if linked_list.head is None: raise EmptyListError("List is empty, cannot insert") position = 1 pointer = linked_list.head insert_at_end = True while pointer: if pointer.data >= data: linked_list.insert_at_position(position, data) insert_at_end = False break pointer = pointer.get_next() position += 1 if insert_at_end: linked_list.insert_at_end(data)
def delete_at_end(self): if self.head is None: raise EmptyListError("List is empty, can't delete.") list_length = self.get_length() if list_length == 1: self.delete_at_beginning() else: pointer = self.head while pointer.get_next(): pointer = pointer.get_next() pointer.get_previous().set_next(None)
def delete_at_beginning(self): if self.head is None: raise EmptyListError("List is empty, can't delete.") if self.get_length() == 1: self.head = None else: pointer = self.head while pointer: if pointer.get_next() == self.head: break pointer = pointer.get_next() temp = self.head self.head = temp.get_next() temp.set_next(None) pointer.set_next(self.head)
def intersecting_node(list1, list2): """ Suppose there are two linked lists of lengths l1 and l2, both of which intersect at some point and become a single linked list. The head of both linked lists are known. The intersecting node of the lists is not known. The number of nodes in each list before intersecting and the lengths of the lists are also unknown. Find the intersecting node. :param SingleLinkedList list1: The first linked linked. :param SingleLinkedList list2: The second linked list. :return: the data of the intersecting node. :rtype: int :raises EmptyListError: if the list is empty. """ if list1 is None or list2 is None: raise EmptyListError( "List(s) is/are empty, can't find intersecting node") l1 = list1.get_length() l2 = list2.get_length() pointer1 = list1.head pointer2 = list2.head d = l1 - l2 if l1 < l2: d = l2 - l1 pointer1 = list2.head pointer2 = list1.head for i in range(d): pointer1 = pointer1.get_next() while pointer1 and pointer2: if pointer1 == pointer2: return pointer2.data pointer1 = pointer1.get_next() pointer2 = pointer2.get_next() return None
def delete_at_position(self, position): """ Position is 1 based. """ if self.head is None: raise EmptyListError("List is empty, can't delete.") list_length = self.get_length() if not (1 <= position <= list_length): raise RangeError( "Position range must be 1 through {0}.".format(list_length)) if position == 1: self.delete_at_beginning() else: pointer = self.head pos = 1 while pos != position - 1: pointer = pointer.get_next() pos += 1 next = pointer.get_next().get_next() pointer.get_next().set_next(None) pointer.set_next(next)
def reverse_single_linked_list(linked_list): """ Reverse a given single linked list. :param SingleLinkedList linked_list: The linked list to operate. :return: nothing. :rtype: None :raises EmptyListError: if the list is empty. """ if linked_list.head is None: raise EmptyListError("List is empty, cannot reverse") previous = None pointer = linked_list.head while pointer: next = pointer.get_next() pointer.set_next(previous) previous = pointer pointer = next linked_list.head = previous
def loop_in_a_list(linked_list): """ Check whether a given linked list ends in a cycle (cyclic). If yes, find the start node of the loop. :param SingleLinkedList linked_list: The linked list to operate. :return: whether cyclic, and also start node if it is cyclic. :rtype: tuple :raises EmptyListError: if the list is empty. """ if linked_list.head is None: raise EmptyListError("List is empty, cannot continue operation") is_cyclic = False slow_ptr = linked_list.head fast_ptr = linked_list.head # fast_ptr traverses two steps at a time, slow_ptr traverses one step at # a time. If they meet at a point, there is a loop in the list. while slow_ptr and fast_ptr and fast_ptr.get_next(): slow_ptr = slow_ptr.get_next() fast_ptr = fast_ptr.get_next().get_next() if fast_ptr == slow_ptr: is_cyclic = True break if is_cyclic: # Set slow_ptr to head node slow_ptr = linked_list.head # Now, traverse both pointers one step a time, the point where they meet # is the beginning of the loop. while slow_ptr != fast_ptr: fast_ptr = fast_ptr.get_next() slow_ptr = slow_ptr.get_next() return is_cyclic, fast_ptr and fast_ptr.data
def delete_at_end(self): if self.head is None: raise EmptyListError("List is empty, can't delete.") list_length = self.get_length() if list_length == 1: self.delete_at_beginning() else: # Keep track of 2 pointers, one is the traversing and # the other one is the node previous to it. The `previous` # moves 1 step ahead after `pointer` has moved 2 steps. pointer = self.head previous = self.head steps = 1 while pointer.get_next(): pointer = pointer.get_next() if steps == 2: previous = previous.get_next() steps = 1 steps += 1 previous.set_next(None)
def lenth_of_the_loop(linked_list): """ Find the length of the loop in a linked list if it exists. :param SingleLinkedList linked_list: The linked list to operate. :return: the count of number of nodes in the loop. :rtype: int :raises EmptyListError: if the list is empty. """ if linked_list.head is None: raise EmptyListError("List is empty, cannot continue operation") is_cyclic = False slow_ptr = linked_list.head fast_ptr = linked_list.head # fast_ptr traverses two steps at a time, slow_ptr traverses one step at # a time. If they meet at a point, there is a loop in the list. while slow_ptr and fast_ptr and fast_ptr.get_next(): slow_ptr = slow_ptr.get_next() fast_ptr = fast_ptr.get_next().get_next() if fast_ptr == slow_ptr: is_cyclic = True break counter = 0 if is_cyclic: # At this point, fast_ptr == slow_ptr. # Keep moving the fast_ptr till it comes back again to slow_ptr, # increasing the counter at each iteration. counter += 1 while slow_ptr != fast_ptr.get_next(): fast_ptr = fast_ptr.get_next() counter += 1 return counter