算法:排序-python

排序

排序中python中,nums.sort()或者sorted()。sorted会更为灵活,目前经常对字典排序也是用sorted key = lambda…的办法进行。
排序的时间复杂O(nlgn)程序中内置的一般是快速排序与归并排序,都是使用了分治的思想。在这两个排序中,会混用插入排序。

还是先从基本的开始。

冒泡排序

def bubble(nums):
    if len(nums) <= 1:
        return nums
    for i in range(len(nums)):
        is_sort = True
        for j in range(0,len(nums)- i - 1):
            if nums[j] > nums[j+1]:
                nums[j],nums[j+1] = nums[j+1],nums[j]
                is_sort = False
        if is_sort:
            break
    return nums

就是遍历数组,相邻两两比较,将最大的放到最后。
改进点:设置一个flag。如果遍历完是有序的,直接退出循环。
时间复杂 O ( n 2 ) O(n^2) O(n2)

选择排序

def selection(nums):
    for i in range(len(nums)):
        idx = len(nums) - i -1
        for j in range(0,len(nums)-i):
            if nums[j] > nums[idx]:
                idx = j
        nums[idx],nums[len(nums)-i-1] = nums[len(nums)-i-1] ,nums[idx]
    return nums

也是遍历数组,找到最大的index,进行交换,放到最后。
时间复杂 O ( n 2 ) O(n^2) O(n2)

插入排序

def insert(nums):
    n = len(nums)
    if n ==0:
        return nums
    for i in range(1,n):
        idx = i
        while idx >= 1 and nums[idx] < nums[idx-1]:
            nums[idx-1],nums[idx] = nums[idx],nums[idx-1]
            idx -=1
    return nums

想想打牌是如何摸牌理牌,每次抽一张后,插入原来摆好的顺序中。
时间复杂 O ( n 2 ) O(n^2) O(n2) 想想最坏情况,每次我都要把摸到的牌放到最前面。

希尔排序

def shell(nums):
    n = len(nums)
    gap = n
    while gap > 0:
        for i in range(gap,n,gap):
            idx = i
            while idx >= gap and  nums[idx] < nums[idx-gap]:
                nums[idx-gap],nums[idx] = nums[idx],nums[idx-gap]
                idx -= gap
        gap = gap // 2
    return nums

对于子列进行插入排序

计数排序

def count(nums):
    if len(nums) == 0:
        return []
    #找到最大最小
    nmin,nmax = nums[0],nums[0]
    for i in nums:
        if i > nmax:nmax = i
        if i < nmin:nmin = i
    #创建放进抽屉
    lens = nmax - nmin + 1
    count = [0]* lens
    for num in nums:
        count[num-nmin] += 1
    #从抽屉中取出
    for i in range(lens):
        for j in range(count[i]):
            nums[i+j] = nmin + i
    return nums

适用于最大最小值差距不是很大的情况。
想想抽屉,我创建m个抽屉,每个抽屉放相同的值。
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( m ) O(m) O(m)

归并排序

def merge_(a,b):
    n,m = len(a),len(b)
    i,j = 0,0
    new = []
    while i < n and j <m:
        if a[i] < b[j]:
            new.append(a[i])
            i += 1
        else :
            new.append(b[j])
            j += 1
    while i < n:
        new.append(a[i])
        i += 1
    while j < m :
        new.append(b[j])
        j += 1
    return new
def merge_sort(nums):
    if len(nums) <= 1:
        return nums
    mid = len(nums)// 2
    left = merge_sort(nums[:mid])
    right = merge_sort(nums[mid:])
    return merge_(left,right)

简单来说,分治我要排序整个数组,我就排序两部分,依次拆下去,然后再合并。
所以需要一个辅助函数。
主函数就是假设每次我排序完的left,right都是有序的,我只要把他们有序合并即可。(因为Base情况就是单个数组,肯定是有序的)

辅助函数可以改进写法:

def _merge(a: list, b: list) -> list:
    """Merge two sorted list"""
    c = []
    while len(a) > 0 and len(b) > 0:
        if a[0] < b[0]:
            c.append(a[0])
            a.remove(a[0])
        else:
            c.append(b[0])
            b.remove(b[0])
    if len(a) == 0:
        c += b
    else:
        c += a
    return c

就是用数组来写,每次添加完就删去,最后就是数组合并。

快速排序

def pivot(nums,t):
    n = len(nums)
    left = [x for x in nums[:] if x < t]
    right = [x for x in nums[:] if x >= t]
    return left + [t] + right 

def quick(nums):
    if len(nums) <= 3:
        return insert(nums) #达到一定小序列插入快速排序
        # <= 1 return nums 是原版
    t = nums[0]
    left = quick([x for x in nums[1:] if x < t])
    right = quick([x for x in nums[1:] if x >= t])

    return left + [t] + right 

快速排序就是每次把一个元素放到正确的位置(即左边都小于它,右边都大于等于它)然后两部分再次进行相同操作。

这个元素怎么选取?最简单就是第一个元素,或者就是 中间元素,头,尾取中间那个。

当base情况,也可以考虑用插入排序,比如长度小于3这样,长度小的插入排序是很快的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值