Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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)