zoukankan      html  css  js  c++  java
  • pyhton3 一些排序算法概括

    1、冒泡算法

    import random
    import datetime
    
    def maopao(data):
        # 检测是否排序完成
        for i in range(len(data)-1):
            flag = False
            for j in range(len(data)-1-i):
                if data[j]>data[j+1]:
                    data[j],data[j+1]=data[j+1],data[j]
                    flag = True
            if not flag:
                break
    
        return data
    
    
    
    test_data=list(range(1,100000))
    random.shuffle(test_data)  #打乱顺序
    time1=datetime.datetime.now()
    print(test_data)
    
    test_data=maopao(test_data)
    time2=datetime.datetime.now()
    
    print(test_data,'readtime:',time2-time1)

    如上排序了100000个乱序的数,耗时0:16:49.345000,性能有点差;

    时间复杂度为O(N^2)

    2、插入排序

    import random
    import datetime
    
    def insertSort(arr):
        length = len(arr)
        for i in range(1,length):
            x = arr[i]
            for j in range(i,-1,-1):
            # j为当前位置,试探j-1位置
                if x < arr[j-1]:
                    arr[j] = arr[j-1]
                else:
                    # 位置确定为j
                    break
            arr[j] = x
        return arr
    
    test_data = list(range(100000))
    random.shuffle(test_data)
    time1=datetime.datetime.now()
    print(test_data)
    
    test_data=insertSort(test_data)
    time2=datetime.datetime.now()
    print(test_data,'readtime:',time2-time1)

    如上排序了100000个乱序的数,耗时 0:06:57.300000,性能一般般;

    时间复杂度为:O(n^2/2)

    3、归并算法

    import random
    import datetime
    
    def merge_sort(li):
        #不断递归调用自己一直到拆分成成单个元素的时候就返回这个元素,不再拆分了
        if len(li) == 1:
            return li
    
        #取拆分的中间位置
        mid = len(li) // 2
        #拆分过后左右两侧子串
        left = li[:mid]
        right = li[mid:]
    
        #对拆分过后的左右再拆分 一直到只有一个元素为止
        #最后一次递归时候ll和lr都会接到一个元素的列表
        # 最后一次递归之前的ll和rl会接收到排好序的子序列
        ll = merge_sort(left)
        rl = merge_sort(right)
    
        # 我们对返回的两个拆分结果进行排序后合并再返回正确顺序的子列表
        # 这里我们调用拎一个函数帮助我们按顺序合并ll和lr
        return merge(ll,rl)
    
    #这里接收两个列表
    def merge(left,right):
        # 从两个有顺序的列表里边依次取数据比较后放入result
        # 每次我们分别拿出两个列表中最小的数比较,把较小的放入result
        result = []
        while len(left)>0 and len(right)>0 :
            #为了保持稳定性,当遇到相等的时候优先把左侧的数放进结果列表,因为left本来也是大数列中比较靠左的
            if left[0] <= right[0]:
                result.append(left.pop(0))
            else:
                result.append(right.pop(0))
        #while循环出来之后 说明其中一个数组没有数据了,我们把另一个数组添加到结果数组后面
        result += left
        result += right
        return result
    
    if __name__ == '__main__':
        li = list(range(100000))
        random.shuffle(li)
        print(li)
        time1=datetime.datetime.now()
        li=merge_sort(li)
        time2=datetime.datetime.now()
        print(li,'readtime:',time2-time1)

    如上排序了100000个乱序的数,耗时0:00:01.712000,性能还可以;

    时间复杂度为:O(N*log(N))

    4、快速排序

    这个排序借鉴一下大佬的文章,原文:https://blog.csdn.net/flyingsbird/article/details/79533075 

    快速排序是一个“交换类”的排序,以军训排队为例,教官说:“第一个同学出列,其他人以他为中心,比他矮的全排到他的左边,比他高的全排他右边。”这就是一趟快速排序。可以看出,一趟快速排序是以一个“枢轴”为中心,将序列分成两部分,枢轴的一边全是比它小(或者小于等于)的,另一边全是比他大(或者大于等于)的。

    原始序列:
        49 38 65 97 76 13 27 49
        i                     j(i和j开始时分别指向头,尾元素)
        进行第一趟快速排序,以第一个数49作为枢纽(通常都选第一个元素作为枢纽),整个过程是一个交替扫描和交换的过程。
        1)使用j,从序列最右端开始向前扫描,直到遇到比枢轴49小的数27,j停在这里。
        49 38 65 97 76 13 27 49
        i                  j
        2)将27交换到序列前端i的位置。
        27 38 65 97 76 13    49
        i                  j
        3)使用i,交换扫描方向,从前向后扫描,直到遇到比较枢轴49大的数65,i停在这里。
        27 38 65 97 76 13    49
              i            j
        4)将65交换到序列后端j的位置。
        27 38    97 76 13 65 49
               i           j
        5)使用j,交换扫描方向,从后向前扫描,直到遇到比枢轴49小的数13,j停在这里。
        27 38    97 76 13 65 49
               i        j
        6)将13交换到i的位置。
        27 38 13 97 76    65 49
               i        j
        7)使用i,交换扫描方向,从前向后扫描,直到遇到比49大的数97,i停在这里。
        27 38 13 97 76    65 49
                 i      j
        8)将97交换到j位置。
        27 38 13    76 97 65 49
                 i      j
        9)使用j,交换扫描方向,直到遇到比49小的数,当扫描到i与j相遇时,说明扫描过程结束了。
        27 38 13    76 97 65 49
                 ij
        10)此时i等于j的这个位置就是枢轴49的最终位置,将49放入这个位置,第一趟快速排序结束。
        27 38 13 49 76 97 65 49
                 ij

    可以看出一次快速排序后,将原来的序列以49为枢轴,划分为两部分,49左边的数都小于或等于它,右边的数都大于或等于它。接下来按照同样的方法对序列{27 38 13}和序列{76 97 65 49}分别进行快速排序。经过几次这样的快速排序,最终得到一个有序的序列。
    快速排序代码如下:

    #!/user/bin/env.python
    # _*_ coding;utf-8 _*_
    # @Time     :2018/10/25 15:02
    import random
    import datetime
    def sub_sort(array,low,high):
        key = array[low]
        while low < high:
            while low < high and array[high] >= key:
                high -= 1
            while low < high and array[high] < key:
                array[low] = array[high]
                low += 1
                array[high] = array[low]
        array[low] = key
        return low
    
    
    def quick_sort(array,low,high):
         if low < high:
            key_index = sub_sort(array,low,high)
            quick_sort(array,low,key_index)
            quick_sort(array,key_index+1,high)
    
    
    if __name__ == '__main__':
        array = list(range(100000))
        random.shuffle(array)
        print(array)
        time1=datetime.datetime.now()
    
        quick_sort(array,0,len(array)-1)
        time2=datetime.datetime.now()
        print(array,'readtime:',time2-time1)

    如上排序了100000个乱序的数,耗时 0:00:00.461000,性能很不错;

    在最优的情况下,快速排序算法的时间复杂度为O(nlogn),同归并排序。

    最糟糕情况下的快排时间复杂度为O(n^2)。

    但空间复杂度低,所以综合起来处理时间比较短。

  • 相关阅读:
    CF995A Tesla
    CF961D Pair Of Lines
    P1186 玛丽卡
    CF986B Petr and Permutations
    hdu6331 Problem M. Walking Plan
    Edison UVALive3488
    Be a Smart Raftsman SGU475
    100198H Royal Federation
    100197G Robbers
    Evil Book -- CodeChef
  • 原文地址:https://www.cnblogs.com/wang666/p/9849712.html
Copyright © 2011-2022 走看看