• 算法——归并和归并排序


    一、归并

      假设现在的列表分两段有序,如何将其合成为一个有序列表。这种操作称为一次归并。

    1、归并过程图示

      当一个列表两段有序合并为一个有序列表的一次归并的过程如下:

      将列表分为两段,两个箭头分别指向每段的第一个:

      

      比较两段中最小的数2和1,将最小的那个值,箭头后移:

      

      接着比较两段中最小的数,将2取出,箭头后移,以此类推:

      

    2、归并代码实现

    def merge(li, low, mid, high):
        """
        归并过程
        :param li:列表
        :param low:第一段第一个元素
        :param mid:第一段最后一个元素
        :param high:第二段最后一个元素
        :return:
        """
        i = low
        j = mid + 1   # 第二段第一个元素
        ltmp = []  # 新列表
        while i <= mid and j<= high:    # 只要左右两边都有数
            if li[i] < li[j]:
                ltmp.append(li[i])
                i += 1
            else:
                ltmp.append(li[j])
                j += 1
        # while执行完,肯定会有一部分没数了
        while i<= mid :   # 如果是第一部分仍有数
            ltmp.append(li[i])
            i += 1
        while j <= high:   # 如果是第二部分仍有数
            ltmp.append(li[j])
            j += 1
        # 将ltmp的值写回到li
        li[low:high+1] = ltmp   # 切片往回写
    
    
    li = [2, 4, 5, 7, 1, 3, 6, 8]
    merge(li, 0, 3, 7)
    print(li)
    """
    [1, 2, 3, 4, 5, 6, 7, 8]
    """

    二、归并排序——使用归并

      归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

    1、归并排序图示

      

      分解:将列表越分越小,直至分成一个元素。

      终止条件:一个元素是有序的。

      合并:将两个有序列表归并,列表越来越大。

    2、归并排序代码实现

    def merge(li, low, mid, high):
        """
        归并过程
        :param li:列表
        :param low:第一段第一个元素
        :param mid:第一段最后一个元素
        :param high:第二段最后一个元素
        :return:
        """
        i = low
        j = mid + 1   # 第二段第一个元素
        ltmp = []  # 新列表
        while i <= mid and j<= high:    # 只要左右两边都有数
            if li[i] < li[j]:
                ltmp.append(li[i])
                i += 1
            else:
                ltmp.append(li[j])
                j += 1
        # while执行完,肯定会有一部分没数了
        while i<= mid :   # 如果是第一部分仍有数
            ltmp.append(li[i])
            i += 1
        while j <= high:   # 如果是第二部分仍有数
            ltmp.append(li[j])
            j += 1
        # 将ltmp的值写回到li
        li[low:high+1] = ltmp   # 切片往回写
    
    
    def _merge_sort(li, low, high):     # 递归函数
        """归并排序"""
        if low < high:    # 翟少有两个元素,递归
            mid = (low + high) // 2
            _merge_sort(li, low, mid)    # 把左边排好序
            _merge_sort(li, mid+1, high)   # 把右边排好序
            merge(li, low, mid, high)
            print(li[low: high+1])
    
    
    def merge_sort(li):
        return _merge_sort(li, 0, len(li)-1)
    
    
    li = list(range(10))
    import random
    random.shuffle(li)
    print(li)
    merge_sort(li)
    print(li)
    """
    [6, 2, 8, 3, 1, 9, 7, 5, 4, 0]
    [2, 6]
    [2, 6, 8]
    [1, 3]
    [1, 2, 3, 6, 8]
    [7, 9]
    [5, 7, 9]
    [0, 4]
    [0, 4, 5, 7, 9]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    """
    

    3、归并和归并排序时间、空间复杂度  

      每一层的时间复杂度是O(n),层数是logn。因此总的时间复杂度是O(nlogn)

      由于merge函数创建了一个ltmp的临时空间,到最大的时候长度是n,空间复杂度是O(n)。不再是原地排序。

  • 相关阅读:
    程序员创业第二步:五个角度打造企业世界级竞争力
    开源题材征集 + MVC&EF Core 完整教程小结
    MVC+EF Core 完整教程20--tag helper详解
    MVC5+EF6 入门完整教程13 -- 动态生成多级菜单
    加载驱动三种的方法
    Caused by: javax.el.PropertyNotFoundException: Property [userName] not found on type [java.lang.String]
    Eclipse 中的 insert spaces for tabs 设置方法
    Windows中mysql的配置文件,解决字符集编码问题,统一使用utf8字符集
    ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated ......问题报错解决办法!
    Java中的类三种类加载器+双气委派模型
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9672639.html
Copyright © 2020-2023  润新知