[排序N大件之]归并排序

终于到归并了吗?归并排序本质上是一个递归的过程,递归到底层,然后按照顺序再向上层归并,这是一个典型运用到分治+递归的思想的排序

算法的核心思想:分治+递归

分治:整个列表是否有序,取决于列表是否局部有序,因此将列表不断分裂成更小的区间,每个区间都依赖于更小的区间的有序,当所有的局部区间有序了,整个列表也就有序了

分治思想的的引入,就是对整个排序算法的不断优化

冒泡——>选择——>插入——谢尔排序——归并排序——快速排序

  • 从谢尔排序开始,引入了[整个列表是否有序取决于局部列表是否有序]这一优化思想去优化插入排序

  • 到归并排序,采用分治算法,不断的[分裂],最后[归并],有序的局部区间逐渐扩大,使整个列表变成有序

  • 快速排序,是更优化的分治思想,它的局部列表不再是随机分的,而是相对于一个'pivot'[基准],在'pivot'左侧的都是比它小的元素,在右侧的都是比它大的元素,就不需要归并排序中对整个列表的归并过程,对空间复杂度有一定的提高?

思路:

  • 将列表不断分裂

  • 直到分裂成最小

  • 然后开始归并

采用递归解法:

  • 递归出口:当局部列表[分裂形成]的长度唯一时,就直接返回

  • 减小问题规模:不断的列表分裂成两半

  • 调用自身:对一半和另一半,进行排序,归并

 

代码如下:

 

def mergeSort(nums):
    
    # 递归出口
    if len(nums) > 1:
        
        # 缩小问题规模
        mid = len(nums) // 2
        left = nums[:mid]
        right = nums[mid:]
        
        # 调用自身,对左右两侧分别进行归并排序:到这里左右两边就是一个已经排序好的了
        mergeSort(left)
        mergeSort(right)
        
        # 最后再对左右两个子列表进行归并就可以了
        i = j = k = 0
        while i < len(left) and j < len(right):
            if left[i] < right[j]:
                nums[k] = left[i]
                i = i + 1
            else:
                nums[k] = right[j]
                j = j + 1
            k = k + 1

        while i < len(left):
            nums[k] = left[i]
            k = k + 1
            i = i + 1

        while j < len(right):
            nums[k] = right[j]
            k = k + 1
            j = j + 1

    return nums

if __name__ == "__main__":
    numbers = [3, 7, 5, 4, 8, 9, 6, 2, 1]
    print(mergeSort(numbers))

 

时间复杂度:O(nlogn),最好最坏都是O(nlogn)

空间复杂度:O(n),因为需要额外的递归栈空间

 

在这里先说一下我所学过的排序方法的稳定性吧:

稳定的排序:冒泡,插入,归并

不稳定的排序:选择,谢尔,快速

 

posted @ 2020-09-23 18:25  剪剪  阅读(96)  评论(0编辑  收藏  举报