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

    注意:

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

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

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

  • 相关阅读:
    LeetCode 109 Convert Sorted List to Binary Search Tree
    LeetCode 108 Convert Sorted Array to Binary Search Tree
    LeetCode 107. Binary Tree Level Order Traversal II
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 103 Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 104. Maximum Depth of Binary Tree
    接口和多态性
    C# 编码规范
  • 原文地址:https://www.cnblogs.com/amou/p/9045949.html
Copyright © 2011-2022 走看看