zoukankan      html  css  js  c++  java
  • 算法学习:归并排序

    1、概念

    归并排序使用了二分法,归根到底的思想还是分而治之。
    拿到一个长数组,将其不停的分为左边和右边两份,然后以此递归分下去。
    将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合 并成一个有序表,称为二路归并。
    归并排序是一种稳定的排序方法。

    2、举例

    1)合并两个有序数组,伪代码

        arr_a = [1,4,5,6]
        arr_b = [4,4,8,10]
    伪代码如下:
        result = []
        idx_a,idx_b
        while idx_a<len(arr_a) and idx_b<len(arr_b):
            if arr_a[idx_a]<=arr_b[idx_b]:
                result[arr_a[idx_a]]
                idx_a+=1
            elif arr_a[idx_a]>arr_b[idx_b]
                result[arr_b[idx_b]]
                idx_b+=1
        if idx_a==len(arr_a):
            result.extend(arr_b[idx_b:])

    2)对于没有顺序的数组排序

     思想:拆拆拆,合合合

    将一个无序的数组从数组的中间部分无限的拆分,形成前后两部分(循环拆分)当我们拆分到数组只有一个元素的时候,这个数组就可以看作是一个有序数组,然后再将前后2个部分合并起来,这样整个数组就有序了。
     
    [11,2,3,43,23,5,6,9,10] len==9 mid =4
    拆:拆分到最有只有一个元素
    [11,2,3,43] [23,5,6,9,10]
    [11,2] [3,43] [23,5] [6,9,10]
    [11] [2] [3] [43] [23] [5] [6] [9,10]
    [11] [2] [3] [43] [23] [5] [6] [9] [10]
    ------------------------------------------------
    合并
    [2,11] [3,43] [5,23] [6,9]
    [2,3,11,43] [5,6,9,23]
    [2,3,5,6,9,11,23,43]
     

    3、代码1:合并两个有序数组

    def mergerArr(arr_a,arr_b):
        """这个是合并2个有序数组的合并算法"""
        result = []
        idx_a =0
        idx_b =0
        #idx_a和idx_b分别执行数组a和数组b的第一个元素,一次比较两个指针指向的元素值,取较小元素放入result,然后挪动指针进行比较
        while idx_a<len(arr_a) and idx_b<len(arr_b):
            if arr_a[idx_a]<=arr_b[idx_b]:
                result.append(arr_a[idx_a])
                idx_a+=1
            elif arr_a[idx_a]>arr_b[idx_b]:
                result.append(arr_b[idx_b])
                idx_b+=1
        #比较结束完了以后,其中一个数组已经取完值了,另外一个数组还没有
        print("idx_a = %s idx_b = %s"%(idx_a,idx_b))
        if idx_a==len(arr_a):
            result.extend(arr_b[idx_b:])
        else:
            result.extend(arr_a[idx_a:])
        return result
    arr_b = [1,4,5,6]
    arr_a = [4,4,8,10]
    print(mergerArr(arr_a,arr_b))
    #结果
    idx_a = 2 idx_b = 4
    [1, 4, 4, 4, 5, 6, 8, 10]

    4、代码2:无序数组拆分过程

    def mergeSort(arr):
        if len(arr)<=1:
            return arr
        mid = len(arr)//2
        left = mergeSort(arr[:mid])
        right = mergeSort(arr[mid:])
        print("left=%s
    right=%s"%(left,right))
            #拆分后,到只剩下一个元素了mid和left才返回值了,才能做合并的过程
        return mergerArr(left,right)
        
    arr = [11,2,3,43,23,5,6,9]
    print(mergeSort(arr))

    5、最终代码

    def mergerArr(arr_a,arr_b):
        """这个是合并2个有序数组的合并算法"""
        result = []
        idx_a =0
        idx_b =0
        #idx_a和idx_b分别执行数组a和数组b的第一个元素,一次比较两个指针指向的元素值,取较小元素放入result,然后挪动指针进行比较
        while idx_a<len(arr_a) and idx_b<len(arr_b):
            if arr_a[idx_a]<=arr_b[idx_b]:
                result.append(arr_a[idx_a])
                idx_a+=1
            elif arr_a[idx_a]>arr_b[idx_b]:
                result.append(arr_b[idx_b])
                idx_b+=1
        #比较结束完了以后,其中一个数组已经取完值了,另外一个数组还没有
        print("idx_a = %s idx_b = %s"%(idx_a,idx_b))
        if idx_a==len(arr_a):
            result.extend(arr_b[idx_b:])
        else:
            result.extend(arr_a[idx_a:])
        return result
    
    def mergeSort(arr):
        if len(arr)<=1:
            return arr
        mid = len(arr)//2
        left = mergeSort(arr[:mid])
        right = mergeSort(arr[mid:])
        print("left=%s
    right=%s"%(left,right))
        #拆分后,到只剩下一个元素了mid和left才返回值了,才能做合并的过程
        return mergerArr(left,right)
        
    arr = [11,2,3,43,23,5,6,9]
    print(mergeSort(arr))

    结果:

     6、时间复杂度

    由于递归拆分的时间复杂度是logN
    然而,进行两个有序数组排序的方法复杂度是N
    该算法的时间复杂度是N*logN
    所以是O(NlogN)
     
    7、快速排序和归并排序
    归并和快排都是用到递归的处理方式。
    归并排序的处理过程是由下到上的,先解决子问题然后再合并的;
    快排和归并正好相反,快排的处理是由上到下的,是先分区然后再去处理子问题。
     
    归并是稳定排序,快排不是稳定排序;
    特殊情况归并的性能比快排稍微好一点。
     

  • 相关阅读:
    HTML框架
    HTML链接
    kzalloc 函数详解(转载)
    LCD接口(转载)
    S3C2440上RTC时钟驱动开发实例讲解(转载)
    PHP 真值与空值
    http chunked 理解
    c# 基础
    美式音标注意事项
    groovy 闭包
  • 原文地址:https://www.cnblogs.com/hqq2019-10/p/14087182.html
Copyright © 2011-2022 走看看