并归排序(Merge Sort)

Last Updated: 2024-02-02 14:49:17 Friday

-- TOC --

又给自己出了一道题:用loop和recursive两种方式实现并归排序,Merge Sort,比较性能。

并归排序如果从上到下实现,就是典型的tree recursive,逻辑清晰。如果从下到上实现,就是采用loop方式,逻辑稍微复杂一点点。并归排序的时间复杂度是\(\Theta(N\log_2{N})\),这是compare-based sorting算法的理论最优时间复杂度。

下面是用Python的两种实现和测试代码:

def merge_sort_recur(data: list[int]) -> list[int]:
    """ merge sort, recursive version """
    if (data_len:=len(data)) <= 1:
        return data

    midx = data_len // 2
    data_l = merge_sort_recur(data[:midx])
    data_r = merge_sort_recur(data[midx:])

    len_l = len(data_l)
    len_r = len(data_r)

    rtv = []
    i = j = 0
    while i<len_l and j<len_r:
        if data_l[i] < data_r[j]:
            rtv.append(data_l[i])
            i += 1
        else:
            rtv.append(data_r[j])
            j += 1

    if i == len_l:
        rtv += data_r[j:]
    else:
        rtv += data_l[i:]

    return rtv


def merge_sort_loop(data: list[int]) -> list[int]:
    """ merge sort, loop version """
    rtv = data[:]  # do not chage input data
    if (data_len:=len(rtv)) <= 1:
        return rtv

    s = 2
    while s < data_len*2:
        i = s // 2
        for j in range(0,data_len,s):
            t = []
            left, right = j, j+i
            while left<j+i and right<j+s and right<data_len:
                if rtv[left] < rtv[right]:
                    t.append(rtv[left])
                    left += 1
                else:
                    t.append(rtv[right])
                    right += 1
            if left == j+i:
                t += rtv[right:j+s]
            else:
                t += rtv[left:j+i]
            rtv[j:j+s] = t
        s *= 2

    return rtv


import random
data = [random.randint(0,int(1e4)) for i in range(int(1e4))]
sorted_data = sorted(data)
assert merge_sort_recur(data) == sorted_data
assert merge_sort_loop(data)  == sorted_data


import time
from timeit import timeit
n = 500
random.shuffle(data)
print('merge_sort_recur:',
      timeit('merge_sort_recur(data)',
             timer=time.process_time,
             number=n,
             globals=globals())/n)
print('merge_sort_loop:',
      timeit('merge_sort_loop(data)',
             timer=time.process_time,
             number=n,
             globals=globals())/n)
print('sorted:',
      timeit('sorted(data)',
             timer=time.process_time,
             number=n,
             globals=globals())/n)

输出:

merge_sort_recur: 0.042351022126000004
merge_sort_loop: 0.051091905257999996
sorted: 0.0013074325759999965

稍微有点以外,recursive的方式更快一点。

思考:

本文链接:https://cs.pynote.net/ag/202307067/

-- EOF --

-- MORE --