Python 算法 | 归并排序

2020-06-04  本文已影响0人  生信师姐

将原数组不断分解为前后两部分, 直到每个数组内只有一个元素, 然后不断进行排序合并, 最后合并为一个有序数组

分析

假设现在的列表分两段有序,如何将其合成为一个有序列表。

思路:
  比较2个列表第一个元素,谁小,谁出来。继续比剩下2个列表的首元素,直到2边只剩下一边是有元素的,另外一边是没有元素的。然后把有元素的一边依次取出来,最后就是一个有序列表了。这种操作称为一次归并

image image image

完整代码

def merge(li, low, mid, high):
    # 列表两段有序: [low, mid] [mid+1, high]
    i = low
    j = mid + 1
    li_tmp = []
    while i <= mid and j <= high:
        if li[i] <= li[j]:
            li_tmp.append(li[i])
            i += 1
        else:
            li_tmp.append(li[j])
            j += 1
    while i <= mid:
        li_tmp.append(li[i])
        i += 1
    while j <= high:
        li_tmp.append(li[j])
        j += 1

    li[low:high+1] = li_tmp

li = [2,5,7,9,1,3,4,6,8]
merge(li,0,3,8)
print(li)
'''
[1, 2, 3, 4, 5, 6, 7, 8, 9]
'''

时间复杂度O(n)

扩展

两个有序列表,合并成一个有序列表(注意是2个,而不是上面的一个两段有序的列表)。整体思路和上面差不多。

def merge2list(li1, li2):
    li = []
    i = 0                                 # i表示li1列表的索引
    j = 0                                 # j表示li2列表的索引
    while i < len(li1) and j < len(li2):  # li1和li2列表里面有值
        if li1[i] <= li2[j]:
            li.append(li1[i])
            i += 1
        else:
            li.append(li2[j])
            j += 1
    while i < len(li1):                  #li1列表里面有剩余值
        li.append(li1[i])
        i += 1
    while j < len(li2):                  # li2列表里面有剩余值     
        li.append(li2[j])
        j += 1
    return li

li1 = [2,5,7,9]
li2 = [1,3,4,6,8]
li = merge2list(li1,li2)
print(li)                               # [1, 2, 3, 4, 5, 6, 7, 8, 9]

有了归并怎么用?
分解:将列表越分越小,直至分成一个元素。
终止条件:一个元素是有序的。
合并:将两个有序列表归并,列表越来越大。

image

归并排序
  在low和high之间一半处递归继续往下分,然后使用上面的一次归并。先递归后执行比先执行后递归慢。

def merge(li, low, mid, high):
    # 列表两段有序: [low, mid] [mid+1, high]
    i = low
    j = mid + 1
    li_tmp = []                                 # x
    while i <= mid and j <= high:               #
        if li[i] <= li[j]:
            li_tmp.append(li[i])
            i += 1
        else:
            li_tmp.append(li[j])
            j += 1
    while i <= mid:
        li_tmp.append(li[i])
        i += 1
    while j <= high:
        li_tmp.append(li[j])
        j += 1
    # li_tmp[0:high-low+1] li[low:high+1]
    # for i in range(low, high+1):
    #     li[i] = li_tmp[i-low]
    li[low:high+1] = li_tmp




def _merge_sort(li, low, high):         # 排序li的low到high的范围
    if low < high:
        mid = (low + high) // 2
        _merge_sort(li, low, mid)
        _merge_sort(li, mid+1, high)
        # print(li[low:mid + 1], li[mid + 1:high + 1])
        merge(li, low, mid, high)
        # print(li[low: high + 1])

@cal_time
def merge_sort(li):
    _merge_sort(li, 0, len(li)-1)

li = list(range(100000))
li.sort()
random.shuffle(li)
merge_sort(li)
#print(li)
上一篇 下一篇

猜你喜欢

热点阅读