高效归并排序(python)

2024-01-19 19:25:59 浏览数 (2)

归并排序

Tips:

代码语言:shell复制
a = b   c*2**k
b =  a % c =   a & (k-1)
c =  a // 2**k = a >> k
代码语言:shell复制
## For example:
643 = 3   20*2**5
3 = 643 % 32 = 643 & 31
20 = 643 // 32 = 643 >> 5
```shell
代码语言:python3复制
import math
from typing import List


def getPower2(n: int):
    """Returns a power of two size for the given target n.
    max is 2**32
    Tips:
        keep moving to the right to make all the bits 1
        From JDK1.8 HashTable.
    """
    if n < 2:
        raise Exception("the number must be greater than 1.")
    n -= 1
    n |= n >> 1
    n |= n >> 2
    n |= n >> 4
    n |= n >> 8
    n |= n >> 16
    return (n 1, int(math.log2(n 1)))


def merge_sort(arr: List[int]):
    """Divide and conquer algorithm.
    Complexity:
        Time: $O(nlogn)$
        Space: $O(1)$
        Stable: yes
    Example:
    >>> raw_data = [0, 10, 15, 9, 3, 13, 21, 6, 8, 10]
    >>> merge_sort(raw_data)
    [0, 3, 6, 8, 9, 10, 10, 13, 15, 21]
    >>> raw_data
    [0, 10, 15, 9, 3, 13, 21, 6, 8, 10]
    """
    # Copy arr, don't change raw data.
    arr = arr[:]
    max_num, power = getPower2(max(arr) 1)

    def merge(left, mid, right):
        """Once merge
        """
        i, j, k = left, mid   1, left
        while i <= mid and j <= right:
            # Compare
            a = arr[i] & (max_num - 1)
            b = arr[j] & (max_num-1)
            if a < b:
                arr[k] = arr[k]   a * max_num
                i  = 1
            else:
                arr[k] = arr[k]   b * max_num
                j  = 1
            k  = 1
        # Checking if any elements was left
        while i <= mid:
            arr[k] = arr[k]   (arr[i] & (max_num - 1)) * max_num
            i  = 1
            k  = 1
        while j <= right:
            arr[k] = arr[k]   (arr[j] & (max_num - 1)) * max_num
            j  = 1
            k  = 1
        # Restore
        for i in range(left, right   1):
            arr[i] >>= power

    def merge_sort_rec(left, right):
        # recurse return point.
        if left >= right:
            return
        mid = (left   right) >> 1
        # Divide
        merge_sort_rec(left, mid)
        merge_sort_rec(mid 1, right)
        merge(left, mid, right)

    merge_sort_rec(0, len(arr) - 1)
    return arr


if __name__ == "__main__":
    import doctest
    doctest.testmod(verbose=True)

0 人点赞