python 冒泡、快速、归并排序

一、冒泡排序(Bubble Sort)

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

 

下面是完整代码:

 

def bubble_sort(l):
    for i in range(len(l)):
        for j in range(len(l) - i - 1):
            if l[j] > l[j+1]:
                l[j], l[j+1] = l[j+1], l[j]
    return l

L = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44]
l = bubble_sort(L)
print(l)

 

二.快速排序(Quick Sort)

  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

先来看一个称之为伪快排的快排代码:

def quick_sort(array):
    if len(array) < 2:
        return array
    else:
        pivot = array[0]
        less_than_pivot = [x for x in array[1:] if x <= pivot]
        more_than_pivot = [x for x in array[1:] if x > pivot]
        return quick_sort(less_than_pivot) + [pivot] + quick_sort(more_than_pivot)

这段代码最关键的是pivot这个参数,这段代码里取序列的第一个元素,然后以这个元素为分组的基准,利用列表解析式使得它左边的值都比它小,右边的值都比它大。然后再分别对这些序列进行递归排序。

这段代码虽然短小利于理解,但是其效率很低,主要体现在以下方面:

  • 分组基准的选取过于随便,不一定可以取到列表的中间值
  • 空间复杂度大,使用了两个列表解析式,而且每次选取进行比较时需要遍历整个序列。
  • 若序列长度过于小(比如只有几个元素),快排效率就不如插入排序了。
  • 递归影响性能,最好进行优化。
 
下面是完整代码:
def partition(arr, left, right):
    key = left  # 划分参考数索引,默认为第一个数为基准数,可优化
    while left < right:
        # 如果列表后边的数,比基准数大或相等,则前移一位直到有比基准数小的数出现
        while left < right and arr[right] >= arr[key]:
            right -= 1
        # 如果列表前边的数,比基准数小或相等,则后移一位直到有比基准数大的数出现
        while left < right and arr[left] <= arr[key]:
            left += 1
        # 此时已找到一个比基准大的书,和一个比基准小的数,将他们互换位置
        (arr[left], arr[right]) = (arr[right], arr[left])

    # 当从两边分别逼近,直到两个位置相等时结束,将左边小的同基准进行交换
    (arr[left], arr[key]) = (arr[key], arr[left])
    # 返回目前基准所在位置的索引
    return left
 
def quicksort(arr, left, right):  
    if left >= right:
        return
    # 从基准开始分区
    mid = partition(arr, left, right)
    # 递归调用
    # print(arr)
    quicksort(arr, left, mid - 1)
    quicksort(arr, mid + 1, right)
    return arr

def Quicksort(arr):
    return quicksort(arr, 0, len(arr)-1)

L = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44]
l = Quicksort(L)
print(l)

 

 

三.二路归并排序(Two-way Merge Sort)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列

 

下面是完整代码:

def merge(arr,left,mid,right):
    temp=[]     #中间数组
    i=left          #左段子序列起始
    j=mid+1   #右段子序列起始
    while i<=mid and j<=right:
        if arr[i]<=arr[j]:
            temp.append(arr[i])
            i+=1
        else:
            temp.append(arr[j])
            j+=1
    while i<=mid:
        temp.append(arr[i])
        i+=1
    while j<=right:
        temp.append(arr[j])
        j+=1
    for i in range(left,right+1):    #  !注意这里,不能直接arr=temp,他俩大小都不一定一样
        arr[i]=temp[i-left]
        
    #递归调用归并排序
def mSort(arr,left,right):
    if left>=right:
        return
    mid=(left+right)//2
    mSort(arr,left,mid)
    mSort(arr,mid+1,right)
    merge(arr,left,mid,right)
    return arr  
  
def MSort(arr):
    return mSort(arr, 0, len(arr)-1)

L = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44]
l = MSort(L)
print(l)

 

posted @ 2019-12-12 11:21  hoo_o  阅读(199)  评论(0编辑  收藏  举报