Bootstrap

排序算法乱炖: 快速排序、归并排序、冒泡排序

一. 快速排序(属于自顶向下)

1. 快速排序原地版

最好情况的时间复杂度:O(nlogn),logn为递归的层数,n为每层递归中总的时间复杂度。
最差情况的时间复杂度:O(n*n)

def quicksort_inplace(left,right): #子数组第一个元素和最后一个元素在原数组中的位置
    if left >= right: #递归终止条件
        return
    l,r,std = left, right, nums[left] #初始化左指针,右指针和基准值
    while r > l:    ##调整元素位置
        while nums[r] >= std and r > l:
            r -= 1
        tmp = nums[l]
        nums[l] = nums[r]
        nums[r] = tmp
        while nums[l] < std and r > l:
            l += 1
        tmp = nums[r]
        nums[r] = nums[l]
        nums[l] = tmp
    quicksort_inplace(left,l)
    quicksort_inplace(l+1,right)
    
nums = [5,3,6,4,1,2,8,7]
quicksort_inplace(0,len(nums)-1)
print(nums)

2. 快速排序空间换时间版

最好情况的时间复杂度:低于O(nlogn)

#快速排序
#没有if if else的用法
def quicksort_basic(arr):
    if len(arr) <= 1:
        return arr
    left = []
    right = []
    mid = []
    std = arr[len(arr) // 2]
    for x in arr:
        if x == std:
            mid.append(x)
        if x < std:
            left.append(x)
        #else:
        if x > std:
            right.append(x)
    return quicksort_basic(left) + mid + quicksort_basic(right)

二. 归并排序(属于自底向上)

思想 :分治。分而治之 ,递归的把数据一分为二,直到数组中只有一个元素为止。归并的把两个有序数组重新排序。返回一个新数组。具体来说归并的意思如下:假设有两个已经有序的列表设定两个指针分别指向这两个列表的起始元素,申请内存空间新建一个空列表,比较两个指针指向的元素大小,将较小的元素添加到新列表中,然后将该指针向该列表的下一个元素偏移,继续比较两个指针指向的元素和添加较小的到新列表中。直到其中一个列表的数据全部被添加完时,把另一个列表中剩下的数据按顺序添加到新列表中。这就实现了将两个有序列表合并成一个新的有序列表的方法。

相比于快排,归并的时间复杂度更稳定:保持O(nlogn),logn为递归的层数,n为每层递归中总的时间复杂度。

#归并排序
nums = [5,3,6,4,1,2,8,7]
def merge_sort(nums):
    if len(nums) <= 1:
        return nums
    left_arr = merge_sort(nums[0:len(nums) // 2])
    right_arr = merge_sort(nums[len(nums) // 2:])
    return merge(left_arr,right_arr)

def merge(left_arr,right_arr):
    rst = []
    pointer1 = 0
    pointer2 = 0
    while pointer1 < len(left_arr) and pointer2 < len(right_arr):
        if left_arr[pointer1] <= right_arr[pointer2]:
            rst.append(left_arr[pointer1])
            pointer1 += 1
        else:
            rst.append(right_arr[pointer2])
            pointer2 += 1
    return rst + right_arr[pointer2:] + left_arr[pointer1:] #技巧:right_arr[pointer2:]中加了冒号就不会报索引超出index的错误
        
rst = merge_sort(nums) 
print(rst)   

三. 冒泡排序

核心原理:用两层for循环,每一次外循环都可以把无序中最小的元素放到有序元素的最开始
最差的时间复杂度: O(n*n)

#冒泡排序
nums = [5,3,6,4,1,2,8,7]
def bubbleSort(nums):
    for i in range(len(nums)):
        for j in range(i+1,len(nums)):
            if nums[j] < nums[i]:
                tmp = nums[j]
                nums[j] = nums[i]
                nums[i] = tmp      
bubbleSort(nums) 
print(nums)   

Refer:
【python算法系列二】快速排序算法
快速排序&归并排序—时间复杂度分析
快速排序和归并排序
Python实现归并排序

;