def __new__(cls, elements=None, heap_property="min", d=4): obj = Heap.__new__(cls) obj.heap_property = heap_property obj.d = d if heap_property == "min": obj._comp = lambda key_parent, key_child: key_parent <= key_child elif heap_property == "max": obj._comp = lambda key_parent, key_child: key_parent >= key_child else: raise ValueError("%s is invalid heap property" % (heap_property)) if elements is None: elements = DynamicOneDimensionalArray(TreeNode, 0) elif _check_type(elements, (list, tuple)): elements = DynamicOneDimensionalArray(TreeNode, len(elements), elements) elif _check_type(elements, Array): elements = DynamicOneDimensionalArray(TreeNode, len(elements), elements._data) else: raise ValueError( f'Expected a list/tuple/Array of TreeNode got {type(elements)}' ) obj.heap = elements obj._last_pos_filled = obj.heap._last_pos_filled obj._build() return obj
def test_Stack(): s = Stack(implementation='array') s1 = Stack() assert _check_type(s, ArrayStack) is True assert _check_type(s1, ArrayStack) is True s2 = Stack(implementation='linked_list') assert _check_type(s2, LinkedListStack) is True assert raises(NotImplementedError, lambda: Stack(implementation=''))
def test_Queue(): q = Queue(implementation='array') q1 = Queue() assert _check_type(q, ArrayQueue) is True assert _check_type(q1, ArrayQueue) is True q2 = Queue(implementation='linked_list') assert _check_type(q2, LinkedListQueue) is True assert raises(NotImplementedError, lambda: Queue(implementation=''))
def __new__(cls, root=None, order=None): if root is not None and not _check_type(root, BinomialTreeNode): raise TypeError("%s i.e., root should be of " "type BinomialTreeNode." % (root)) if order is not None and not _check_type(order, int): raise TypeError("%s i.e., order should be of " "type int." % (order)) obj = object.__new__(cls) if root is not None: root.is_root = True obj.root = root obj.order = order return obj
def __new__(cls, root=None, order=None, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) if root is not None and \ not _check_type(root, BinomialTreeNode): raise TypeError("%s i.e., root should be of " "type BinomialTreeNode." % (root)) if order is not None and not _check_type(order, int): raise TypeError("%s i.e., order should be of " "type int." % (order)) obj = object.__new__(cls) if root is not None: root.is_root = True obj.root = root obj.order = order return obj
def __setitem__(self, idx, elem): if elem is None: self._data[idx] = None else: if _check_type(elem, self._dtype) is False: elem = self._dtype(elem) self._data[idx] = elem
def merge_sort_parallel(array, num_threads, **kwargs): """ Implements parallel merge sort. Parameters ========== array: Array The array which is to be sorted. num_threads: int The maximum number of threads to be used for sorting. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for sorting. If the function returns False then only swapping is performed. Optional, by default, less than or equal to is used for comparing two values. Examples ======== >>> from pydatastructs import OneDimensionalArray, merge_sort_parallel >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> merge_sort_parallel(arr, 3) >>> [arr[0], arr[1], arr[2]] [1, 2, 3] >>> merge_sort_parallel(arr, 3, comp=lambda u, v: u > v) >>> [arr[0], arr[1], arr[2]] [3, 2, 1] References ========== .. [1] https://en.wikipedia.org/wiki/Merge_sort """ start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) comp = kwargs.get("comp", lambda u, v: u <= v) for size in range(floor(log(end - start + 1, 2)) + 1): pow_2 = 2**size with ThreadPoolExecutor(max_workers=num_threads) as Executor: i = start while i <= end: Executor.submit(_merge, array, i, i + pow_2 - 1, i + pow_2, i + 2 * pow_2 - 1, end, comp).result() i = i + 2 * pow_2 if _check_type(array, DynamicArray): array._modify(force=True)
def __new__(cls, root_list=[]): if not all((_check_type(root, BinomialTree)) for root in root_list): raise TypeError("The root_list should contain " "references to objects of BinomialTree.") obj = Heap.__new__(cls) obj.root_list = root_list return obj
def brick_sort(array, **kwargs): """ Implements Brick Sort / Odd Even sorting algorithm Parameters ========== array: Array The array which is to be sorted. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for sorting. If the function returns False then only swapping is performed. Optional, by default, less than or equal to is used for comparing two values. Examples ======== >>> from pydatastructs import OneDimensionalArray, brick_sort >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> brick_sort(arr) >>> [arr[0], arr[1], arr[2]] [1, 2, 3] >>> brick_sort(arr, comp=lambda u, v: u > v) >>> [arr[0], arr[1], arr[2]] [3, 2, 1] References ========== .. [1] https://www.geeksforgeeks.org/odd-even-sort-brick-sort/ """ start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) comp = kwargs.get("comp", lambda u, v: u <= v) is_sorted = False while is_sorted is False: is_sorted = True for i in range(start + 1, end, 2): if _comp(array[i + 1], array[i], comp): array[i], array[i + 1] = array[i + 1], array[i] is_sorted = False for i in range(start, end, 2): if _comp(array[i + 1], array[i], comp): array[i], array[i + 1] = array[i + 1], array[i] is_sorted = False if _check_type(array, DynamicArray): array._modify(force=True)
def heapsort(array, **kwargs): """ Implements Heapsort algorithm. Parameters ========== array: Array The array which is to be sorted. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. Examples ======== >>> from pydatastructs import OneDimensionalArray, heapsort >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> heapsort(arr) >>> [arr[0], arr[1], arr[2]] [1, 2, 3] References ========== .. [1] https://en.wikipedia.org/wiki/Heapsort Note ==== This function does not support custom comparators as is the case with other sorting functions in this file. """ from pydatastructs.trees.heaps import BinaryHeap start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) h = BinaryHeap(heap_property="min") for i in range(start, end + 1): if array[i] is not None: h.insert(array[i]) array[i] = None i = start while not h.is_empty: array[i] = h.extract().key i += 1 if _check_type(array, DynamicArray): array._modify(force=True)
def __new__(cls, dtype=NoneType, *args, **kwargs): backend = kwargs.get('backend', Backend.PYTHON) if backend == Backend.CPP: return _arrays.OneDimensionalArray(dtype, *args, **kwargs) if dtype is NoneType: raise ValueError("Data type is not defined.") if len(args) not in (1, 2): raise ValueError("Too few arguments to create a 1D array," " pass either size of the array" " or list of elements or both.") obj = Array.__new__(cls) obj._dtype = dtype if len(args) == 2: if _check_type(args[0], list) and \ _check_type(args[1], int): for i in range(len(args[0])): if _check_type(args[0][i], dtype) is False: args[0][i] = dtype(args[0][i]) size, data = args[1], list(args[0]) elif _check_type(args[1], list) and \ _check_type(args[0], int): for i in range(len(args[1])): if _check_type(args[1][i], dtype) is False: args[1][i] = dtype(args[1][i]) size, data = args[0], list(args[1]) else: raise TypeError("Expected type of size is int and " "expected type of data is list/tuple.") if size != len(data): raise ValueError("Conflict in the size, %s and length of data, %s" %(size, len(data))) obj._size, obj._data = size, data elif len(args) == 1: if _check_type(args[0], int): obj._size = args[0] init = kwargs.get('init', None) obj._data = [init for i in range(args[0])] elif _check_type(args[0], (list, tuple)): for i in range(len(args[0])): if _check_type(args[0][i], dtype) is False: args[0][i] = dtype(args[0][i]) obj._size, obj._data = len(args[0]), \ list(args[0]) else: raise TypeError("Expected type of size is int and " "expected type of data is list/tuple.") return obj
def __new__(cls, root_list=None, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) if root_list is None: root_list = [] if not all((_check_type(root, BinomialTree)) for root in root_list): raise TypeError("The root_list should contain " "references to objects of BinomialTree.") obj = Heap.__new__(cls) obj.root_list = root_list return obj
def merge_tree(self, tree1, tree2): """ Merges two BinomialTree objects. Parameters ========== tree1: BinomialTree tree2: BinomialTree """ if (not _check_type(tree1, BinomialTree)) or (not _check_type( tree2, BinomialTree)): raise TypeError("Both the trees should be of type " "BinomalTree.") if tree1.root.key <= tree2.root.key: tree1.add_sub_tree(tree2) ret_value = tree1 else: tree2.add_sub_tree(tree1) ret_value = tree2 return ret_value
def __new__(cls, dtype=NoneType, *args, **kwargs): if dtype == NoneType or len(args) not in (1, 2): raise ValueError("1D array cannot be created due to incorrect" " information.") obj = object.__new__(cls) obj._dtype = dtype if len(args) == 2: if _check_type(args[0], (list, tuple)) and \ _check_type(args[1], int): size, data = args[1], [dtype(arg) for arg in args[0]] elif _check_type(args[1], (list, tuple)) and \ _check_type(args[0], int): size, data = args[0], [dtype(arg) for arg in args[1]] else: raise TypeError("Expected type of size is int and " "expected type of data is list/tuple.") if size != len(data): raise ValueError( "Conflict in the size %s and length of data %s" % (size, len(data))) obj._size, obj._data = size, data elif len(args) == 1: if _check_type(args[0], int): obj._size = args[0] init = kwargs.get('init', None) obj._data = [init for i in range(args[0])] elif _check_type(args[0], (list, tuple)): obj._size, obj._data = len(args[0]), \ [dtype(arg) for arg in args[0]] else: raise TypeError("Expected type of size is int and " "expected type of data is list/tuple.") return obj
def merge_sort_parallel(array, num_threads, **kwargs): """ Implements parallel merge sort. Parameters ========== array: Array The array which is to be sorted. num_threads: int The maximum number of threads to be used for sorting. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. Examples ======== >>> from pydatastructs import OneDimensionalArray, merge_sort_parallel >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> merge_sort_parallel(arr, 3) >>> [arr[0], arr[1], arr[2]] [1, 2, 3] References ========== .. [1] https://en.wikipedia.org/wiki/Merge_sort """ start = kwargs.get('start', 0) end = kwargs.get('end', array._size - 1) for size in range(floor(log(end - start + 1, 2)) + 1): pow_2 = 2**size with ThreadPoolExecutor(max_workers=num_threads) as Executor: i = start while i <= end: Executor.submit(_merge, array, i, i + pow_2 - 1, i + pow_2, i + 2 * pow_2 - 1, end).result() i = i + 2 * pow_2 if _check_type(array, DynamicArray): array._modify(force=True)
def merge(self, other_heap): """ Merges current binomial heap with the given binomial heap. Parameters ========== other_heap: BinomialHeap """ if not _check_type(other_heap, BinomialHeap): raise TypeError("Other heap is not of type BinomialHeap.") new_root_list = [] i, j = 0, 0 while (i < len(self.root_list)) and \ (j < len(other_heap.root_list)): new_tree = None while self.root_list[i] is None: i += 1 while other_heap.root_list[j] is None: j += 1 if self.root_list[i].order == other_heap.root_list[j].order: new_tree = self.merge_tree(self.root_list[i], other_heap.root_list[j]) i += 1 j += 1 else: if self.root_list[i].order < other_heap.root_list[j].order: new_tree = self.root_list[i] i += 1 else: new_tree = other_heap.root_list[j] j += 1 self._merge_heap_last_new_tree(new_root_list, new_tree) while i < len(self.root_list): new_tree = self.root_list[i] self._merge_heap_last_new_tree(new_root_list, new_tree) i += 1 while j < len(other_heap.root_list): new_tree = other_heap.root_list[j] self._merge_heap_last_new_tree(new_root_list, new_tree) j += 1 self.root_list = new_root_list
def merge(self, other_heap): """ Merges current binomial heap with the given binomial heap. Parameters ========== other_heap: BinomialHeap """ if not _check_type(other_heap, BinomialHeap): raise TypeError("Other heap is not of type BinomialHeap.") new_root_list = DynamicOneDimensionalArray(BinomialTree, 0) i, j = 0, 0 while ((i <= self.root_list._last_pos_filled) and (j <= other_heap.root_list._last_pos_filled)): new_tree = None while self.root_list[i] is None: i += 1 while other_heap.root_list[j] is None: j += 1 if self.root_list[i].order == other_heap.root_list[j].order: new_tree = self.merge_tree(self.root_list[i], other_heap.root_list[j]) i += 1 j += 1 else: if self.root_list[i].order < other_heap.root_list[j].order: new_tree = self.root_list[i] i += 1 else: new_tree = other_heap.root_list[j] j += 1 self._merge_heap_last_new_tree(new_root_list, new_tree) while i <= self.root_list._last_pos_filled: new_tree = self.root_list[i] self._merge_heap_last_new_tree(new_root_list, new_tree) i += 1 while j <= other_heap.root_list._last_pos_filled: new_tree = other_heap.root_list[j] self._merge_heap_last_new_tree(new_root_list, new_tree) j += 1 self.root_list = new_root_list
def __new__(cls, elements=None, heap_property="min", d=4): obj = Heap.__new__(cls) obj.heap_property = heap_property obj.d = d if heap_property == "min": obj._comp = lambda key_parent, key_child: key_parent <= key_child elif heap_property == "max": obj._comp = lambda key_parent, key_child: key_parent >= key_child else: raise ValueError("%s is invalid heap property" % (heap_property)) if elements is None: elements = DynamicOneDimensionalArray(TreeNode, 0) else: if not all(map(lambda x: _check_type(x, TreeNode), elements)): raise ValueError("Expect a list/tuple of TreeNode got %s" % (elements)) obj.heap = elements obj._last_pos_filled = obj.heap._last_pos_filled obj._build() return obj
def query(self, qx, init_node=None): """ Queries the segment tree. Parameters ========== qx: int/float The query point init_node: int The index of the node from which the query process is to be started. Returns ======= intervals: set The set of the intervals which contain the query point. References ========== .. [1] https://en.wikipedia.org/wiki/Segment_tree """ if not self.cache: self.build() if init_node is None: init_node = self.root_idx qn = TreeNode([True, qx, qx, True], None) intervals = [] calls = [init_node] while calls: idx = calls.pop() if _check_type(self.tree[idx].data, list): intervals.extend(self.tree[idx].data) calls = self._iterate(calls, qn, idx) return set(intervals)
def add_sub_tree(self, other_tree): """ Adds a sub tree to current tree. Parameters ========== other_tree: BinomialTree Raises ====== ValueError: If order of the two trees are different. """ if not _check_type(other_tree, BinomialTree): raise TypeError("%s i.e., other_tree should be of " "type BinomialTree" % (other_tree)) if self.order != other_tree.order: raise ValueError("Orders of both the trees should be same.") self.root.children.append(other_tree.root) other_tree.root.parent = self.root other_tree.root.is_root = False self.order += 1
def timsort(array : Array,start,end)-> Array: """ The Timsort algorithm is considered a hybrid sorting algorithm because it employs a best-of-both-worlds combination of insertion sort and merge sort. The main characteristic of Timsort is that it takes advantage of already-sorted elements that exist in most real-world datasets.These are called natural runs. The algorithm then iterates over the list, collecting the elements into runs and merging them into a single sorted list. """ """ Parameters ======== array: Array The required array to be sorted start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. Returns ======= output: Array The sorted list or array Examples ======== >>> from pydatastructs import OneDimensionalArray, timsort >>> arr = OneDimensionalArray(int,[-2, 7, 15, -14, 0, 15, 0] ) >>> timsort(arr, 0, 14) >>> [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6]] [ -14, -2, 0, 0, 7, 15, 15] >>> from pydatastructs import OneDimensionalArray, timsort >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> timsort(arr, 0, 2) >>> [arr[0], arr[1], arr[2]] [1, 2, 3] References ========== .. [1] https://en.wikipedia.org/wiki/Timsort """ min_run = 32 n = len(array) # Start by slicing and sorting small portions of the # input array. The size of these slices is defined by # your `min_run` size. for i in range(0, n, min_run): insertion_sort(array, i, min((i + min_run - 1), n - 1)) # Now you can start merging the sorted slices. # Start from `min_run`, doubling the size on # each iteration until you surpass the length of # the array. size = min_run while size < n: # Determine the arrays that will # be merged together for start in range(0, n, size * 2): # Compute the `midpoint` (where the first array ends # and the second starts) and the `endpoint` (where # the second array ends) midpoint = start + size - 1 end = min((start + size * 2 - 1), (n-1)) # Merge the two subarrays. # The `left` array should go from `start` to # `midpoint + 1`, while the `right` array should # go from `midpoint + 1` to `end + 1`. merged_array = _merge( left= array[start:midpoint + 1], right= array[midpoint + 1:end + 1] ) # Finally, put the merged array back into # your array array[start:start + len(merged_array)] = merged_array # Each iteration should double the size of your arrays size *= 2 if _check_type(array, DynamicArray): array._modify(force=True)
def insertion_sort(array, **kwargs): """ Implements insertion sort algorithm. Parameters ========== array: Array The array which is to be sorted. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for sorting. If the function returns False then only swapping is performed. Optional, by default, less than or equal to is used for comparing two values. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= output: Array The sorted array. Examples ======== >>> from pydatastructs import OneDimensionalArray, insertion_sort >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> out = insertion_sort(arr) >>> str(out) '[1, 2, 3]' >>> out = insertion_sort(arr, comp=lambda u, v: u > v) >>> str(out) '[3, 2, 1]' References ========== .. [1] https://en.wikipedia.org/wiki/Insertion_sort """ raise_if_backend_is_not_python(insertion_sort, kwargs.get('backend', Backend.PYTHON)) start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) comp = kwargs.get('comp', lambda u, v: u <= v) for i in range(start + 1, end + 1): temp = array[i] j = i while j > start and not _comp(array[j - 1], temp, comp): array[j] = array[j - 1] j -= 1 array[j] = temp if _check_type(array, DynamicArray): array._modify(force=True) return array
def test_PriorityQueue(): pq1 = PriorityQueue(implementation='linked_list') assert _check_type(pq1, LinkedListPriorityQueue) is True assert raises(NotImplementedError, lambda: Queue(implementation=''))
def bucket_sort(array: Array, **kwargs) -> Array: """ Performs bucket sort on the given array. Parameters ========== array: Array The array which is to be sorted. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. Returns ======= output: Array The sorted array. Examples ======== >>> from pydatastructs import DynamicOneDimensionalArray as DODA, bucket_sort >>> arr = DODA(int, [5, 78, 1, 0]) >>> out = bucket_sort(arr) >>> str(out) "['0', '1', '5', '78']" >>> arr.delete(2) >>> out = bucket_sort(arr) >>> str(out) "['0', '1', '78']" References ========== .. [1] https://en.wikipedia.org/wiki/Bucket_sort Note ==== This function does not support custom comparators as is the case with other sorting functions in this file. The ouput array doesn't contain any `None` value. """ start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) #Find maximum value in the list and use length of the list to determine which value in the list goes into which bucket max_value = None for i in range(start, end + 1): if array[i] is not None: max_value = array[i] count = 0 for i in range(start, end + 1): if array[i] is not None: count += 1 if array[i] > max_value: max_value = array[i] number_of_null_values = end - start + 1 - count size = max_value // count # Create n empty buckets where n is equal to the length of the input list buckets_list = [[] for _ in range(count)] # Put list elements into different buckets based on the size for i in range(start, end + 1): if array[i] is not None: j = array[i] // size if j is not count: buckets_list[j].append(array[i]) else: buckets_list[count - 1].append(array[i]) # Sort elements within the buckets using Insertion Sort for z in range(count): _bucket_sort_helper(buckets_list[z]) # Concatenate buckets with sorted elements into a single array sorted_list = [] for x in range(count): sorted_list.extend(buckets_list[x]) for i in range(end, end - number_of_null_values, -1): array[i] = None for i in range(start, end - number_of_null_values + 1): array[i] = sorted_list[i - start] if _check_type(array, DynamicArray): array._modify(force=True) return array
def counting_sort(array: Array) -> Array: """ Performs counting sort on the given array. Parameters ========== array: Array The array which is to be sorted. Returns ======= output: Array The sorted array. Examples ======== >>> from pydatastructs import DynamicOneDimensionalArray as DODA, counting_sort >>> arr = DODA(int, [5, 78, 1, 0]) >>> out = counting_sort(arr) >>> str(out) "['0', '1', '5', '78']" >>> arr.delete(2) >>> out = counting_sort(arr) >>> str(out) "['0', '5', '78']" References ========== .. [1] https://en.wikipedia.org/wiki/Counting_sort Note ==== Since, counting sort is a non-comparison sorting algorithm, custom comparators aren't allowed. The ouput array doesn't contain any `None` value. """ max_val, min_val = array[0], array[0] none_count = 0 for i in range(len(array)): if array[i] is not None: if max_val is None or max_val < array[i]: max_val = array[i] if min_val is None or array[i] < min_val: min_val = array[i] else: none_count += 1 if min_val is None or max_val is None: return array count = [0 for _ in range(max_val - min_val + 1)] for i in range(len(array)): if array[i] is not None: count[array[i] - min_val] += 1 total = 0 for i in range(max_val - min_val + 1): count[i], total = total, count[i] + total output = type(array)( array._dtype, [array[i] for i in range(len(array)) if array[i] is not None]) if _check_type(output, DynamicArray): output._modify(force=True) for i in range(len(array)): x = array[i] if x is not None: output[count[x - min_val]] = x count[x - min_val] += 1 return output
def brick_sort_parallel(array, num_threads, **kwargs): """ Implements Concurrent Brick Sort / Odd Even sorting algorithm Parameters ========== array: Array/list The array which is to be sorted. num_threads: int The maximum number of threads to be used for sorting. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for sorting. If the function returns False then only swapping is performed. Optional, by default, less than or equal to is used for comparing two values. Examples ======== >>> from pydatastructs import OneDimensionalArray, brick_sort_parallel >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> brick_sort_parallel(arr, num_threads=5) >>> [arr[0], arr[1], arr[2]] [1, 2, 3] >>> brick_sort_parallel(arr, num_threads=5, comp=lambda u, v: u > v) >>> [arr[0], arr[1], arr[2]] [3, 2, 1] References ========== .. [1] https://en.wikipedia.org/wiki/Odd%E2%80%93even_sort """ start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) comp = kwargs.get("comp", lambda u, v: u <= v) is_sorted = [False] with ThreadPoolExecutor(max_workers=num_threads) as Executor: while is_sorted[0] is False: is_sorted[0] = True for i in range(start + 1, end, 2): Executor.submit(_brick_sort_swap, array, i, i + 1, comp, is_sorted).result() for i in range(start, end, 2): Executor.submit(_brick_sort_swap, array, i, i + 1, comp, is_sorted).result() if _check_type(array, DynamicArray): array._modify(force=True)
def quick_sort(array: Array, **kwargs) -> Array: """ Performs quick sort on the given array. Parameters ========== array: Array The array which is to be sorted. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for sorting. If the function returns False then only swapping is performed. Optional, by default, less than or equal to is used for comparing two values. pick_pivot_element: lambda/function The function implementing the pivot picking logic for quick sort. Should accept, `low`, `high`, and `array` in this order, where `low` represents the left end of the current partition, `high` represents the right end, and `array` is the original input array to `quick_sort` function. Optional, by default, picks the element at `high` index of the current partition as pivot. Returns ======= output: Array The sorted array. Examples ======== >>> from pydatastructs import OneDimensionalArray as ODA, quick_sort >>> arr = ODA(int, [5, 78, 1, 0]) >>> out = quick_sort(arr) >>> str(out) '[0, 1, 5, 78]' >>> arr = ODA(int, [21, 37, 5]) >>> out = quick_sort(arr) >>> str(out) '[5, 21, 37]' References ========== .. [1] https://en.wikipedia.org/wiki/Quicksort """ from pydatastructs import Stack comp = kwargs.get("comp", lambda u, v: u <= v) pick_pivot_element = kwargs.get("pick_pivot_element", lambda low, high, array: array[high]) def partition(low, high, pick_pivot_element): i = (low - 1) x = pick_pivot_element(low, high, array) for j in range(low, high): if _comp(array[j], x, comp) is True: i = i + 1 array[i], array[j] = array[j], array[i] array[i + 1], array[high] = array[high], array[i + 1] return (i + 1) lower = kwargs.get('start', 0) upper = kwargs.get('end', len(array) - 1) stack = Stack() stack.push(lower) stack.push(upper) while stack.is_empty is False: high = stack.pop() low = stack.pop() p = partition(low, high, pick_pivot_element) if p - 1 > low: stack.push(low) stack.push(p - 1) if p + 1 < high: stack.push(p + 1) stack.push(high) if _check_type(array, DynamicArray): array._modify(force=True) return array
def cocktail_shaker_sort(array: Array, **kwargs) -> Array: """ Performs cocktail sort on the given array. Parameters ========== array: Array The array which is to be sorted. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for sorting. If the function returns False then only swapping is performed. Optional, by default, less than or equal to is used for comparing two values. Returns ======= output: Array The sorted array. Examples ======== >>> from pydatastructs import OneDimensionalArray as ODA, cocktail_shaker_sort >>> arr = ODA(int, [5, 78, 1, 0]) >>> out = cocktail_shaker_sort(arr) >>> str(out) '[0, 1, 5, 78]' >>> arr = ODA(int, [21, 37, 5]) >>> out = cocktail_shaker_sort(arr) >>> str(out) '[5, 21, 37]' References ========== .. [1] https://en.wikipedia.org/wiki/Cocktail_shaker_sort """ def swap(i, j): array[i], array[j] = array[j], array[i] lower = kwargs.get('start', 0) upper = kwargs.get('end', len(array) - 1) comp = kwargs.get("comp", lambda u, v: u <= v) swapping = False while (not swapping and upper - lower >= 1): swapping = True for j in range(lower, upper): if _comp(array[j], array[j + 1], comp) is False: swap(j + 1, j) swapping = False upper = upper - 1 for j in range(upper, lower, -1): if _comp(array[j - 1], array[j], comp) is False: swap(j, j - 1) swapping = False lower = lower + 1 if _check_type(array, DynamicArray): array._modify(force=True) return array