def three_way_partition(a_list: list, from_: int, to_: int) -> Tuple[int, int]: """ tree way partition that split the array to the tree parts lesser, equal and greater than the partitioning element :param a_list: list to partition :param from_: partition from here :param to_: partition to here :return: lt and gt separators """ v = a_list[from_] i = from_ lt = from_ gt = to_ while i <= gt: if a_list[i] < v: swap(a_list, i, lt) i += 1 lt += 1 elif a_list[i] > v: swap(a_list, i, gt) gt -= 1 else: i += 1 return lt, gt
def three_way_sort(a_list, low, hi): """ recursive implementation of quick sort with three way partitioning :param a_list: a list to sort :param low: sort from this index :param hi: sort to this index """ if hi <= low: return lt = low gt = hi v = a_list[low] i = low while i <= gt: if a_list[i] < v: swap(a_list, lt, i) lt += 1 i += 1 elif a_list[i] > v: swap(a_list, i, gt) gt -= 1 else: i += 1 three_way_sort(a_list, low, lt -1) three_way_sort(a_list, gt + 1, hi)
def partition(a_list: list, low: int, hi: int) -> int: """ function to partition a list on the first element in such a way that all elements on the left of the array are lower then the partitioning element and everything to the right is higher :param a_list: a list to partition :param low: partition from this index :param hi: partition to this index :return: final position of the partitioning element """ i = low + 1 j = hi while i <= j: while less(a_list[low], a_list[j]): j -= 1 if j <= low: break while less(a_list[i], a_list[low]): i += 1 if i >= hi: break if i >= j: break swap(a_list, i, j) swap(a_list, low, j) return j
def swim(self, index: int): """ swim element at the given index to fix heap order :param index: index of element to swim """ while index > 1 and self.compare(self.data[index], self.data[index // 2]): swap(self.data, index, index // 2) index //= 2
def knuth_shuffle(a_list: list): """ performs inplace knuth shuffle produces uniformly random permutation of the list complexity O(N) :param a_list: list to shuffle """ for i in range(len(a_list)): j = randint(0, i) swap(a_list, i, j)
def heap_sort(a_list: list): """ performs in place heap sort using principles of binary heap complexity O(N log N) :param a_list: a list to sort """ for i in range(len(a_list) // 2, -1, -1): sink(a_list, i, len(a_list) - 1) for i in range(len(a_list)): swap(a_list, 0, len(a_list) - i - 1) sink(a_list, 0, len(a_list) - i - 2)
def remove(self) -> Any: """ remove smallest element from the heap complexity O(log N) :return: smallest element """ data = self.data[1] swap(self.data, 1, self.current_size) self.data[self.current_size] = None self.current_size -= 1 self.sink(1) return data
def insertion_sort(a_list: list, h: int = 1): """ performs inplace insertion sort on a_list Goes through the whole list and moves each element to the left until its in the correct place. complexity 0(N^2) ...~1/4 N^2 :param a_list: a_list to sort :param h length of exchanges """ list_len = len(a_list) for i in range(list_len): j = i while j >= h and less(a_list[j], a_list[j-h]): swap(a_list, j, j-h) j -= h
def selection_sort(a_list: list): """ performs inplace selection sort on a_list. The function searches for the smallest element in the list and moves it the the beginning of the list. Then it searches for the smallest element in the reminder of the list (excluding the first element) and moves it to the second position in the list and so on. complexity O(N^2) ...~1/2 N^2 :param a_list: list to sort """ list_length = len(a_list) for i in range(list_length): min_index = i for j in range(i, list_length): if less(a_list[j], a_list[min_index]): min_index = j swap(a_list, i, min_index)
def sink(self, index: int): """ sink element at the given index to fix heap order :param index: index of element to sink """ while 2 * index <= self.current_size: if self.current_size < 2 * index + 1: _child = 2 * index elif self.compare(self.data[2 * index], self.data[2 * index + 1]): _child = 2 * index else: _child = 2 * index + 1 if self.compare(self.data[_child], self.data[index]): swap(self.data, _child, index) index = _child else: break
def sink(a_list: list, k: int, n: int): """ sink operation for heap sort :param a_list: a list in which to perform the sink :param k: sink element on this index :param n: sink only up to this index """ while (k + 1) * 2 <= n + 1: left_child = 2 * (k + 1) - 1 right_child = min(2 * (k + 1), n) if a_list[left_child] < a_list[right_child]: bigger_child = right_child else: bigger_child = left_child if a_list[bigger_child] > a_list[k]: swap(a_list, k, bigger_child) k = bigger_child else: break