zoukankan      html  css  js  c++  java
  • 归并排序

    归并排序

    描述:

      归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组

      合并:

        将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。

    分析演示:

    时间复杂度:

      最优时间复杂度: O(nlogn)
      最坏时间复杂度: O(nlogn)

    描述:

      归并排序只有一种情况, 所以最优和最坏的复杂度是一样的

    分析:

      归并排序是由两部分组成的: 拆分, 合并   

      拆分:

        将列表一分为二, 一直拆, 直到被拆分为一个个长度为一的小列表, 每次拆一半, 拆n次, 就会把列表拆分完
        因此: 分析的时间复杂度为 O(log2^n)

      合并:

        合并: 先比较左右两个列表内的元素, 然后进行归位, 也就是合并
        因此: 合并的时间复杂度为 O(n)

      优化:

        O(T) = O(n * log2^n) = O(nlogn)

    稳定性: 稳定

      描述:

          因为列表拆分与合并都是由左至右依次执行的, 合并的判断条件是, 如果左列表的元素小于等于右列表的元素, 将元素添加到新列表内, 如果两个元素相等, 左侧的元素先添加到新的列表内, 相对顺序并没有改变

    代码:

    简洁版:

    def merge_sort(Li):
        n = len(Li)
        if n <= 1:
            return Li
        mid = n // 2
        left_Li = merge_sort(Li[:mid])
        right_li = merge_sort(Li[mid:])
        left_pointer, right_pointer = 0, 0
        result = []
        while left_pointer < len(left_Li) and right_pointer < len(right_li):
            if left_Li[left_pointer] <= right_li[right_pointer]:
                result.append(left_Li[left_pointer])
                left_pointer += 1
            else:
                result.append(right_li[right_pointer])
                right_pointer += 1
        result += left_Li[left_pointer:]
        result += right_li[right_pointer:]
        return result
    View Code

    注释版:

    """先拆分, 后归并,
    拆分: 递归调用merge_sort(), 将整个列表拆分成n个小列表, 小列表的长度为1
    归并: 当列表拆分完毕之后, 执行下面的代码, 先进行比较然后进行归位, 然后返回函数的引用
    """
    import random
    
    
    def merge_sort(Li):
        # 先判断传递进来的列表的长度, 如果列表的长度小于等于1, 直接返回
        # 列表的长度小于等于1, 分两种情况
        # 1. 起始传递进来的就是一个空列表或列表只有一个元素, 那么将他返回
        # 2. 在merge_sort()函数体内, 将起始的列表进行拆分, 被拆分之后的小列表, 如果长度为一, 则不能再进行拆分, 将小列表返回
        n = len(Li)
        if n <= 1:
            return Li
        mid = n // 2
        # 1. 设置列表的中间下标, 将原来的列表进行切片, 产生两个新的列表: 左列表, 右列表.
        # 2. 分别对这两个列表, 执行merge_sort()函数
        # 3. 其实merge_sort()函数, 是先对列表进行拆分, 拆分完毕之后, 再将挨着的两个列表进行合并
    
        left_Li = merge_sort(Li[:mid])
        right_li = merge_sort(Li[mid:])
    
        left_pointer, right_pointer = 0, 0
        # 设置两个指针, 分别指向两个列表
        result = []
        # 设置一个空列表, 将比对之后的元素, 追加到这个列表内
    
        while left_pointer < len(left_Li) and right_pointer < len(right_li):
            # 遍历两个列表, 如果其中一个列表遍历完毕, 则终止循环
            if left_Li[left_pointer] <= right_li[right_pointer]:
                # 如果左列表的元素, 小于等于右列表的元素, 将元素追加到新列表内
                # 指针向后移动
                result.append(left_Li[left_pointer])
                left_pointer += 1
    
            else:
                # 如果左列表的元素, 大于右列表的元素, 将右列表的元素追加到新列表内
                # 指针向后移动
                result.append(right_li[right_pointer])
                right_pointer += 1
        # 上面循环结束后, 代表其中一个列表遍历完毕, 将另外列表的内的元素追加到新列表内
        # 然后将新列表返回
        result += left_Li[left_pointer:]
        result += right_li[right_pointer:]
        return result
        # 因为这个函数是递归调用[自己调用自己], 当递归到底的时候, 执行合并, 合并完毕, 返回调用, 然后再次执行合并
    
    
    if __name__ == "__main__":
        l = list(i for i in range(0, 10000 ))
        print("洗牌之前的列表:" + str(l))
        random.shuffle(l)
        print("洗牌之后的列表:" + str(l))
        print(merge_sort(l))
    View Code

    注意:

      归并排序相较于其他排序来说,

      归并排序时产生了新的列表, 消耗内存, 效率降低

      其他列表只是在原列表的基础上进行操作的

  • 相关阅读:
    程序运行时被用户删除了工作目录后崩溃
    const引用与非const引用
    NDKr10的各种BUG
    《区块链100问》第64集:区块链分叉是什么?
    《区块链100问》第65集:比特币生孩子了
    《区块链100问》第66集:软分叉和硬分叉是什么?
    《区块链100问》第67集:重放攻击是什么?
    《区块链100问》第68集:硬分叉之以太经典
    《区块链100问》第69集:区块链项目的分类和应用
    《区块链100问》第70集:区块链项目之币类
  • 原文地址:https://www.cnblogs.com/amou/p/9045949.html
Copyright © 2011-2022 走看看